cmdop 0.1.29__tar.gz → 0.1.30__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.
- {cmdop-0.1.29 → cmdop-0.1.30}/PKG-INFO +1 -1
- {cmdop-0.1.29 → cmdop-0.1.30}/pyproject.toml +1 -1
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/__init__.py +11 -1
- cmdop-0.1.30/src/cmdop/helpers/__init__.py +27 -0
- cmdop-0.1.30/src/cmdop/helpers/desktop.py +350 -0
- cmdop-0.1.29/src/cmdop/helpers/__init__.py +0 -13
- {cmdop-0.1.29 → cmdop-0.1.30}/.gitignore +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/LICENSE +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/README.md +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/agent_messages_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/agent_messages_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/agent_messages_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/common_types_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/common_types_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/common_types_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/control_messages_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/control_messages_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/control_messages_pb2_grpc.py +0 -0
- {cmdop-0.1.29/src/cmdop/_generated/rpc_messages → cmdop-0.1.30/src/cmdop/_generated/file_operations}/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/archive_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/archive_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/archive_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/changes_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/changes_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/changes_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/common_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/common_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/common_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/directory_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/directory_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/directory_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/file_crud_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/file_crud_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/file_crud_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/hls_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/hls_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/hls_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/requests_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/requests_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/requests_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/search_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/search_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/search_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/transfer_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/transfer_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations/transfer_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_operations_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/archive_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/archive_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/archive_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/directory_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/directory_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/directory_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/file_crud_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/file_crud_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/file_crud_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/hls_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/hls_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/hls_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/search_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/search_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc/search_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/file_rpc_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/message_pool.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/py.typed +0 -0
- {cmdop-0.1.29/src/cmdop/_generated/file_operations → cmdop-0.1.30/src/cmdop/_generated/rpc_messages}/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/agent_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/agent_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/agent_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/browser_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/browser_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/browser_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/device_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/device_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/device_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/extract_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/extract_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/extract_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/health_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/health_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/health_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/history_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/history_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/history_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/lifecycle_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/push_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/push_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/push_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/session_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/session_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/session_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/terminal_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/terminal_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages/terminal_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/rpc_messages_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/service_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/service_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/service_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/tunnel_pb2.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/tunnel_pb2.pyi +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/_generated/tunnel_pb2_grpc.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/enums.py +0 -0
- {cmdop-0.1.29/src/cmdop/api/generated/workspaces → cmdop-0.1.30/src/cmdop/api/generated/machines}/logger.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machine_sharing/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machine_sharing/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machine_sharing/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machine_sharing/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machines/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machines/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machines/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/machines__api__machines/sync_client.py +0 -0
- {cmdop-0.1.29/src/cmdop/api/generated/workspaces → cmdop-0.1.30/src/cmdop/api/generated/machines}/retry.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/schema.json +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/machines/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/enums.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/logger.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/retry.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/schema.json +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__oauth/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__oauth/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__oauth/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__oauth/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__system/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__system/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__system/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/system/system__api__system/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/enums.py +0 -0
- {cmdop-0.1.29/src/cmdop/api/generated/machines → cmdop-0.1.30/src/cmdop/api/generated/workspaces}/logger.py +0 -0
- {cmdop-0.1.29/src/cmdop/api/generated/machines → cmdop-0.1.30/src/cmdop/api/generated/workspaces}/retry.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/schema.json +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/sync_client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/client.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/config.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/discovery.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/exceptions.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/helpers/network_analyzer.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/logging.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/agent.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/base.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/config.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/extract.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/files.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/models/terminal.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/py.typed +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/agent.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/base.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/_base.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/_helpers.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/dom.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/fetch.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/input.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/network.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/scroll.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/timing.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/capabilities/visual.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/js/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/js/core.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/js/fetch.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/js/interaction.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/js/scroll.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/models.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/parsing.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/service/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/service/_helpers.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/service/aio.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/service/sync.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/browser/session.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/extract.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/files.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/services/terminal.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/streaming/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/streaming/base.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/streaming/handlers.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/streaming/terminal.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/__init__.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/auth.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/base.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/discovery.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/local.py +0 -0
- {cmdop-0.1.29 → cmdop-0.1.30}/src/cmdop/transport/remote.py +0 -0
|
@@ -120,6 +120,11 @@ from cmdop.helpers import (
|
|
|
120
120
|
NetworkAnalyzer,
|
|
121
121
|
NetworkSnapshot,
|
|
122
122
|
RequestSnapshot,
|
|
123
|
+
# Desktop management
|
|
124
|
+
ensure_desktop_running,
|
|
125
|
+
start_desktop,
|
|
126
|
+
handle_cmdop_error,
|
|
127
|
+
with_auto_restart,
|
|
123
128
|
)
|
|
124
129
|
from cmdop.logging import (
|
|
125
130
|
get_logger,
|
|
@@ -128,7 +133,7 @@ from cmdop.logging import (
|
|
|
128
133
|
get_log_dir,
|
|
129
134
|
)
|
|
130
135
|
|
|
131
|
-
__version__ = "0.1.
|
|
136
|
+
__version__ = "0.1.30"
|
|
132
137
|
|
|
133
138
|
__all__ = [
|
|
134
139
|
# Version
|
|
@@ -225,6 +230,11 @@ __all__ = [
|
|
|
225
230
|
"NetworkAnalyzer",
|
|
226
231
|
"NetworkSnapshot",
|
|
227
232
|
"RequestSnapshot",
|
|
233
|
+
# Desktop management
|
|
234
|
+
"ensure_desktop_running",
|
|
235
|
+
"start_desktop",
|
|
236
|
+
"handle_cmdop_error",
|
|
237
|
+
"with_auto_restart",
|
|
228
238
|
# Logging
|
|
229
239
|
"get_logger",
|
|
230
240
|
"setup_logging",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""CMDOP SDK helpers."""
|
|
2
|
+
|
|
3
|
+
from cmdop.helpers.network_analyzer import (
|
|
4
|
+
NetworkAnalyzer,
|
|
5
|
+
NetworkSnapshot,
|
|
6
|
+
RequestSnapshot,
|
|
7
|
+
)
|
|
8
|
+
from cmdop.helpers.desktop import (
|
|
9
|
+
ensure_desktop_running,
|
|
10
|
+
start_desktop,
|
|
11
|
+
handle_cmdop_error,
|
|
12
|
+
with_auto_restart,
|
|
13
|
+
get_cmdop_app_path,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
# Network
|
|
18
|
+
"NetworkAnalyzer",
|
|
19
|
+
"NetworkSnapshot",
|
|
20
|
+
"RequestSnapshot",
|
|
21
|
+
# Desktop management
|
|
22
|
+
"ensure_desktop_running",
|
|
23
|
+
"start_desktop",
|
|
24
|
+
"handle_cmdop_error",
|
|
25
|
+
"with_auto_restart",
|
|
26
|
+
"get_cmdop_app_path",
|
|
27
|
+
]
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CMDOP Desktop management helpers.
|
|
3
|
+
|
|
4
|
+
Cross-platform utilities for starting, stopping, and ensuring
|
|
5
|
+
CMDOP Desktop is running.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import platform
|
|
11
|
+
import subprocess
|
|
12
|
+
import sys
|
|
13
|
+
import time
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Callable, TypeVar
|
|
16
|
+
|
|
17
|
+
from cmdop.exceptions import AgentNotRunningError, StalePortFileError
|
|
18
|
+
from cmdop.transport.discovery import discover_agent, cleanup_stale_discovery
|
|
19
|
+
|
|
20
|
+
T = TypeVar("T")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# =============================================================================
|
|
24
|
+
# Platform-specific paths
|
|
25
|
+
# =============================================================================
|
|
26
|
+
|
|
27
|
+
def get_cmdop_app_path() -> Path | None:
|
|
28
|
+
"""Get platform-specific path to CMDOP Desktop app."""
|
|
29
|
+
system = platform.system()
|
|
30
|
+
|
|
31
|
+
if system == "Darwin":
|
|
32
|
+
path = Path("/Applications/CMDOP.app")
|
|
33
|
+
if path.exists():
|
|
34
|
+
return path
|
|
35
|
+
# Check user Applications
|
|
36
|
+
user_path = Path.home() / "Applications" / "CMDOP.app"
|
|
37
|
+
if user_path.exists():
|
|
38
|
+
return user_path
|
|
39
|
+
|
|
40
|
+
elif system == "Windows":
|
|
41
|
+
# Common Windows install locations
|
|
42
|
+
paths = [
|
|
43
|
+
Path(r"C:\Program Files\CMDOP\CMDOP.exe"),
|
|
44
|
+
Path(r"C:\Program Files (x86)\CMDOP\CMDOP.exe"),
|
|
45
|
+
Path.home() / "AppData" / "Local" / "Programs" / "CMDOP" / "CMDOP.exe",
|
|
46
|
+
]
|
|
47
|
+
for path in paths:
|
|
48
|
+
if path.exists():
|
|
49
|
+
return path
|
|
50
|
+
|
|
51
|
+
elif system == "Linux":
|
|
52
|
+
# Linux: check if cmdop binary is available
|
|
53
|
+
try:
|
|
54
|
+
result = subprocess.run(
|
|
55
|
+
["which", "cmdop"],
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
)
|
|
59
|
+
if result.returncode == 0:
|
|
60
|
+
return Path(result.stdout.strip())
|
|
61
|
+
except Exception:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# =============================================================================
|
|
68
|
+
# Core functions
|
|
69
|
+
# =============================================================================
|
|
70
|
+
|
|
71
|
+
def start_desktop(timeout: float = 15.0, quiet: bool = False) -> bool:
|
|
72
|
+
"""
|
|
73
|
+
Start CMDOP Desktop application.
|
|
74
|
+
|
|
75
|
+
Cross-platform function that starts CMDOP Desktop and waits
|
|
76
|
+
for the agent to become available.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
timeout: Maximum time to wait for agent to start (seconds)
|
|
80
|
+
quiet: If True, suppress output messages
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
True if agent started successfully, False otherwise
|
|
84
|
+
"""
|
|
85
|
+
system = platform.system()
|
|
86
|
+
|
|
87
|
+
def log(msg: str) -> None:
|
|
88
|
+
if not quiet:
|
|
89
|
+
print(msg)
|
|
90
|
+
|
|
91
|
+
log("🔄 Starting CMDOP Desktop...")
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
if system == "Darwin":
|
|
95
|
+
app_path = get_cmdop_app_path()
|
|
96
|
+
if app_path:
|
|
97
|
+
subprocess.Popen(
|
|
98
|
+
["open", str(app_path)],
|
|
99
|
+
stdout=subprocess.DEVNULL,
|
|
100
|
+
stderr=subprocess.DEVNULL,
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
log("❌ CMDOP.app not found in /Applications")
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
elif system == "Windows":
|
|
107
|
+
app_path = get_cmdop_app_path()
|
|
108
|
+
# DETACHED_PROCESS = 0x00000008
|
|
109
|
+
detached_process = 0x00000008
|
|
110
|
+
if app_path:
|
|
111
|
+
subprocess.Popen(
|
|
112
|
+
[str(app_path)],
|
|
113
|
+
stdout=subprocess.DEVNULL,
|
|
114
|
+
stderr=subprocess.DEVNULL,
|
|
115
|
+
creationflags=detached_process,
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
# Try start command as fallback
|
|
119
|
+
subprocess.Popen(
|
|
120
|
+
["cmd", "/c", "start", "", "CMDOP"],
|
|
121
|
+
stdout=subprocess.DEVNULL,
|
|
122
|
+
stderr=subprocess.DEVNULL,
|
|
123
|
+
shell=True,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
elif system == "Linux":
|
|
127
|
+
# Linux: start cmdop serve in background
|
|
128
|
+
subprocess.Popen(
|
|
129
|
+
["cmdop", "serve"],
|
|
130
|
+
stdout=subprocess.DEVNULL,
|
|
131
|
+
stderr=subprocess.DEVNULL,
|
|
132
|
+
start_new_session=True,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
else:
|
|
136
|
+
log(f"❌ Unsupported platform: {system}")
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
except Exception as e:
|
|
140
|
+
log(f"❌ Failed to start CMDOP: {e}")
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
log("⏳ Waiting for CMDOP to initialize...")
|
|
144
|
+
|
|
145
|
+
# Poll until agent is available
|
|
146
|
+
start_time = time.time()
|
|
147
|
+
last_dot_time = start_time
|
|
148
|
+
|
|
149
|
+
while time.time() - start_time < timeout:
|
|
150
|
+
result = discover_agent(verify_alive=True)
|
|
151
|
+
if result.found:
|
|
152
|
+
log("✅ CMDOP Desktop started successfully")
|
|
153
|
+
return True
|
|
154
|
+
|
|
155
|
+
# Print dots to show progress
|
|
156
|
+
if not quiet and time.time() - last_dot_time >= 1.0:
|
|
157
|
+
print(".", end="", flush=True)
|
|
158
|
+
last_dot_time = time.time()
|
|
159
|
+
|
|
160
|
+
time.sleep(0.3)
|
|
161
|
+
|
|
162
|
+
if not quiet:
|
|
163
|
+
print() # Newline after dots
|
|
164
|
+
log(f"❌ CMDOP did not start within {timeout}s")
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def ensure_desktop_running(
|
|
169
|
+
timeout: float = 15.0,
|
|
170
|
+
auto_start: bool = True,
|
|
171
|
+
exit_on_failure: bool = True,
|
|
172
|
+
) -> bool:
|
|
173
|
+
"""
|
|
174
|
+
Ensure CMDOP Desktop is running, starting it if needed.
|
|
175
|
+
|
|
176
|
+
This is the main function to use before browser operations.
|
|
177
|
+
Handles stale discovery files automatically.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
timeout: Time to wait for agent if starting
|
|
181
|
+
auto_start: If True, attempt to start CMDOP if not running
|
|
182
|
+
exit_on_failure: If True, call sys.exit(1) on failure
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
True if CMDOP is running
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
SystemExit: If exit_on_failure=True and CMDOP cannot be started
|
|
189
|
+
|
|
190
|
+
Example:
|
|
191
|
+
>>> from cmdop.helpers import ensure_desktop_running
|
|
192
|
+
>>> ensure_desktop_running() # Starts CMDOP if needed
|
|
193
|
+
>>> # Now safe to use browser
|
|
194
|
+
>>> client = CMDOPClient.local()
|
|
195
|
+
"""
|
|
196
|
+
result = discover_agent(verify_alive=True)
|
|
197
|
+
|
|
198
|
+
if result.found:
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
# Handle stale discovery file
|
|
202
|
+
if result.discovery_path:
|
|
203
|
+
print(f"⚠️ Cleaning stale discovery file: {result.discovery_path}")
|
|
204
|
+
cleanup_stale_discovery(result.discovery_path)
|
|
205
|
+
|
|
206
|
+
print("⚠️ CMDOP Desktop is not running")
|
|
207
|
+
|
|
208
|
+
if not auto_start:
|
|
209
|
+
if exit_on_failure:
|
|
210
|
+
print("\nStart CMDOP Desktop manually:")
|
|
211
|
+
_print_start_instructions()
|
|
212
|
+
sys.exit(1)
|
|
213
|
+
return False
|
|
214
|
+
|
|
215
|
+
# Try to start
|
|
216
|
+
if start_desktop(timeout=timeout):
|
|
217
|
+
return True
|
|
218
|
+
|
|
219
|
+
if exit_on_failure:
|
|
220
|
+
print("\n💡 Try starting CMDOP Desktop manually:")
|
|
221
|
+
_print_start_instructions()
|
|
222
|
+
sys.exit(1)
|
|
223
|
+
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def handle_cmdop_error(
|
|
228
|
+
error: Exception,
|
|
229
|
+
auto_restart: bool = True,
|
|
230
|
+
exit_on_failure: bool = True,
|
|
231
|
+
) -> bool:
|
|
232
|
+
"""
|
|
233
|
+
Handle CMDOP connection errors with auto-restart.
|
|
234
|
+
|
|
235
|
+
Use this in except blocks to handle AgentNotRunningError
|
|
236
|
+
and StalePortFileError gracefully.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
error: The exception that was raised
|
|
240
|
+
auto_restart: If True, attempt to restart CMDOP
|
|
241
|
+
exit_on_failure: If True, call sys.exit(1) if restart fails
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
True if CMDOP was restarted successfully
|
|
245
|
+
|
|
246
|
+
Example:
|
|
247
|
+
>>> try:
|
|
248
|
+
... client = CMDOPClient.local()
|
|
249
|
+
... session = client.browser.create_session()
|
|
250
|
+
... except (StalePortFileError, AgentNotRunningError) as e:
|
|
251
|
+
... if handle_cmdop_error(e):
|
|
252
|
+
... # Retry the operation
|
|
253
|
+
... client = CMDOPClient.local()
|
|
254
|
+
"""
|
|
255
|
+
if isinstance(error, StalePortFileError):
|
|
256
|
+
print(f"\n⚠️ CMDOP Desktop crashed (stale file: {error.discovery_path})")
|
|
257
|
+
error.cleanup()
|
|
258
|
+
elif isinstance(error, AgentNotRunningError):
|
|
259
|
+
print("\n⚠️ CMDOP Desktop is not running")
|
|
260
|
+
else:
|
|
261
|
+
# Unknown error, re-raise
|
|
262
|
+
raise error
|
|
263
|
+
|
|
264
|
+
if not auto_restart:
|
|
265
|
+
if exit_on_failure:
|
|
266
|
+
print("\nStart CMDOP Desktop:")
|
|
267
|
+
_print_start_instructions()
|
|
268
|
+
sys.exit(1)
|
|
269
|
+
return False
|
|
270
|
+
|
|
271
|
+
if start_desktop():
|
|
272
|
+
return True
|
|
273
|
+
|
|
274
|
+
if exit_on_failure:
|
|
275
|
+
print("\n💡 Try starting CMDOP Desktop manually:")
|
|
276
|
+
_print_start_instructions()
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
|
|
279
|
+
return False
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def with_auto_restart(
|
|
283
|
+
func: Callable[..., T],
|
|
284
|
+
*args,
|
|
285
|
+
max_retries: int = 1,
|
|
286
|
+
**kwargs,
|
|
287
|
+
) -> T:
|
|
288
|
+
"""
|
|
289
|
+
Execute function with automatic CMDOP restart on failure.
|
|
290
|
+
|
|
291
|
+
Wraps a function that uses CMDOP and automatically handles
|
|
292
|
+
connection errors by restarting CMDOP Desktop.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
func: Function to execute
|
|
296
|
+
*args: Arguments to pass to function
|
|
297
|
+
max_retries: Maximum restart attempts
|
|
298
|
+
**kwargs: Keyword arguments to pass to function
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
Result of the function
|
|
302
|
+
|
|
303
|
+
Example:
|
|
304
|
+
>>> def parse_page():
|
|
305
|
+
... client = CMDOPClient.local()
|
|
306
|
+
... with client.browser.create_session() as session:
|
|
307
|
+
... session.navigate("https://example.com")
|
|
308
|
+
... return session.get_text("body")
|
|
309
|
+
...
|
|
310
|
+
>>> result = with_auto_restart(parse_page)
|
|
311
|
+
"""
|
|
312
|
+
last_error: Exception | None = None
|
|
313
|
+
|
|
314
|
+
for attempt in range(max_retries + 1):
|
|
315
|
+
try:
|
|
316
|
+
return func(*args, **kwargs)
|
|
317
|
+
except (StalePortFileError, AgentNotRunningError) as e:
|
|
318
|
+
last_error = e
|
|
319
|
+
|
|
320
|
+
if attempt < max_retries:
|
|
321
|
+
print(f"\n🔄 CMDOP error (attempt {attempt + 1}/{max_retries + 1})")
|
|
322
|
+
if handle_cmdop_error(e, auto_restart=True, exit_on_failure=False):
|
|
323
|
+
continue
|
|
324
|
+
|
|
325
|
+
# Last attempt failed
|
|
326
|
+
handle_cmdop_error(e, auto_restart=False, exit_on_failure=True)
|
|
327
|
+
|
|
328
|
+
# Should not reach here, but just in case
|
|
329
|
+
if last_error:
|
|
330
|
+
raise last_error
|
|
331
|
+
raise RuntimeError("Unexpected error in with_auto_restart")
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# =============================================================================
|
|
335
|
+
# Private helpers
|
|
336
|
+
# =============================================================================
|
|
337
|
+
|
|
338
|
+
def _print_start_instructions() -> None:
|
|
339
|
+
"""Print platform-specific start instructions."""
|
|
340
|
+
system = platform.system()
|
|
341
|
+
|
|
342
|
+
if system == "Darwin":
|
|
343
|
+
print(" open /Applications/CMDOP.app")
|
|
344
|
+
elif system == "Windows":
|
|
345
|
+
print(" Start CMDOP from Start Menu")
|
|
346
|
+
print(" or run: CMDOP.exe")
|
|
347
|
+
elif system == "Linux":
|
|
348
|
+
print(" cmdop serve")
|
|
349
|
+
else:
|
|
350
|
+
print(" Start CMDOP Desktop application")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|