Metadata-Version: 2.4
Name: cmdop
Version: 0.1.0
Summary: Python SDK for CMDOP agent interaction
Project-URL: Homepage, https://cmdop.com
Project-URL: Documentation, https://cmdop.com
Project-URL: Repository, https://github.com/markolofsen/cmdop-client
Author: CMDOP Team
License: MIT
License-File: LICENSE
Keywords: agent,automation,cmdop,grpc,terminal
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: grpcio>=1.60.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: protobuf>=4.25.0
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: pydantic>=2.5.0
Provides-Extra: dev
Requires-Dist: grpcio-tools>=1.60.0; extra == 'dev'
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-grpc-aio>=0.3.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Description-Content-Type: text/markdown

# cmdop

Python SDK for [CMDOP](https://cmdop.com) — remote terminal and file management for your machines.

[![PyPI](https://img.shields.io/pypi/v/cmdop)](https://pypi.org/project/cmdop/)
[![Python](https://img.shields.io/pypi/pyversions/cmdop)](https://pypi.org/project/cmdop/)
[![License](https://img.shields.io/pypi/l/cmdop)](https://github.com/cmdop/cmdop-python/blob/main/LICENSE)

## Installation

```bash
pip install cmdop
```

## Quick Start

```python
from cmdop import CMDOPClient

with CMDOPClient.remote(api_key="cmdop_live_xxx") as client:
    # Terminal
    session = client.terminal.create()
    client.terminal.send_input(session.session_id, "ls -la\n")

    # Files
    files = client.files.list("/home")
    content = client.files.read("/etc/hostname")
```

## Features

| Feature | Description |
|---------|-------------|
| **Remote Mode** | Connect via cloud relay (grpc.cmdop.com) |
| **Local Mode** | Direct IPC with local agent (Unix socket) |
| **Sync & Async** | Both `CMDOPClient` and `AsyncCMDOPClient` |
| **Terminal** | Create sessions, send input, resize, signals |
| **Files** | List, read, write, copy, move, delete |
| **Type Safe** | Full Pydantic v2 models |

## Connection Modes

```python
# Remote — via cloud relay
client = CMDOPClient.remote(api_key="cmdop_live_xxx")

# Local — direct to agent
client = CMDOPClient.local()
```

## Async Usage

```python
import asyncio
from cmdop import AsyncCMDOPClient

async def main():
    async with AsyncCMDOPClient.remote(api_key="cmdop_live_xxx") as client:
        session = await client.terminal.create()
        await client.terminal.send_input(session.session_id, "whoami\n")

        files = await client.files.list("/tmp")

asyncio.run(main())
```

## API Reference

### Terminal Service

| Method | Description |
|--------|-------------|
| `create(shell, cols, rows)` | Create terminal session |
| `send_input(session_id, data)` | Send input to terminal |
| `resize(session_id, cols, rows)` | Resize terminal |
| `send_signal(session_id, signal)` | Send signal (SIGINT, etc.) |
| `get_history(session_id, lines)` | Get output history |
| `close(session_id)` | Close session |

### Files Service

| Method | Description |
|--------|-------------|
| `list(path, limit, offset)` | List directory contents |
| `read(path)` | Read file contents |
| `write(path, content)` | Write file |
| `delete(path, recursive)` | Delete file or directory |
| `copy(src, dst)` | Copy file |
| `move(src, dst)` | Move/rename file |
| `mkdir(path, parents)` | Create directory |
| `info(path)` | Get file metadata |

## Error Handling

```python
from cmdop import CMDOPClient
from cmdop.exceptions import (
    AgentOfflineError,
    AuthenticationError,
    SessionNotFoundError,
    FileNotFoundError,
)

try:
    client = CMDOPClient.remote(api_key="cmdop_live_xxx")
    client.terminal.create()
except AuthenticationError:
    print("Invalid API key")
except AgentOfflineError:
    print("Agent not connected")
```

## Configuration

```python
from cmdop import CMDOPClient
from cmdop.models import ConnectionConfig, KeepaliveConfig

config = ConnectionConfig(
    connect_timeout_seconds=10.0,
    request_timeout_seconds=30.0,
    keepalive=KeepaliveConfig(time_ms=10_000, timeout_ms=5_000),
)

client = CMDOPClient.remote(api_key="cmdop_live_xxx", config=config)
```

## Requirements

- Python 3.10+
- grpcio, protobuf
- pydantic v2
- httpx

## License

MIT
