Metadata-Version: 2.4
Name: mobilerun-core-cli
Version: 0.2.0
Summary: Slim async local device drivers for Android Portal and iOS Portal, extracted from mobilerun.
Project-URL: Homepage, https://github.com/droidrun/mobilerun-core-cli
Project-URL: Repository, https://github.com/droidrun/mobilerun-core-cli
Project-URL: Bug Tracker, https://github.com/droidrun/mobilerun-core-cli/issues
Project-URL: Upstream, https://github.com/droidrun/mobilerun
Author: droidrun
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Hardware
Requires-Python: <3.14,>=3.11
Requires-Dist: async-adbutils
Requires-Dist: httpx>=0.27.0
Requires-Dist: requests>=2.31
Requires-Dist: rich>=14.1.0
Description-Content-Type: text/markdown

<picture align="center">
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/droidrun/mobilerun/main/static/mobilerun-dark.png">
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/droidrun/mobilerun/main/static/mobilerun.png">
  <img src="https://raw.githubusercontent.com/droidrun/mobilerun/main/static/mobilerun.png" width="full">
</picture>

<p align="center">
  <strong>mobilerun-core-cli is the slim async local-driver core of <a href="https://github.com/droidrun/mobilerun">mobilerun</a>.</strong><br>
  No CLI, no agent, no LLM providers — just local Android/iOS drivers for higher-level tools such as <code>mobilerun-core</code>.
</p>

<div align="center">

<a href="https://docs.mobilerun.ai">📕 Documentation</a>
·
<a href="https://github.com/droidrun/mobilerun">🧠 mobilerun framework</a>
·
<a href="https://pypi.org/project/mobilerun-core-cli/">📦 PyPI</a>

[![PyPI version](https://img.shields.io/pypi/v/mobilerun-core-cli?style=flat-square)](https://pypi.org/project/mobilerun-core-cli/)
[![Python](https://img.shields.io/pypi/pyversions/mobilerun-core-cli?style=flat-square)](https://pypi.org/project/mobilerun-core-cli/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](./LICENSE)
[![Discord](https://img.shields.io/discord/1360219330318696488?color=white&label=Discord&logo=discord&logoColor=white&style=flat-square)](https://discord.gg/ZZbKEZZkwK)

</div>

---

- 📱 Drive local devices — Android over ADB+Portal, Android Portal HTTP-only, or iOS Portal HTTP.
- ⚡ TCP-with-content-provider fallback — fast Android HTTP path over `adb forward`, transparent fallback to content-provider RPC.
- 🔌 HTTP-only drivers — connect to already-running Android/iOS portals without taking over setup.
- 🛠 Portal lifecycle — download, install, accessibility enablement, auto-upgrade.
- 🪶 Slim — a small async driver package with four runtime deps (`async_adbutils`, `httpx`, `requests`, `rich`).
- 🔌 Embeddable — designed to be wrapped by sync facades (e.g. `mobilerun-core`) or used directly.
- 🤝 In sync with upstream — verbatim slice of [`droidrun/mobilerun`](https://github.com/droidrun/mobilerun); behaviour and API track upstream.

## 📦 Installation

> **Note:** Python `>=3.11,<3.14`. The Android ADB driver requires [ADB](https://developer.android.com/studio/releases/platform-tools) on `PATH` and a device with USB debugging enabled. HTTP-only drivers require an already-running portal URL.

```bash
uv pip install mobilerun-core-cli
```

## 🚀 Quick usage

```python
import asyncio
from async_adbutils import adb
from mobilerun_core_cli import AndroidDriver, ensure_portal_ready


async def main():
    # 1. Make sure Portal is installed + accessibility is on.
    device = await adb.device()
    await ensure_portal_ready(device)

    # 2. Drive the device.
    driver = AndroidDriver(serial=device.serial, use_tcp=True)
    await driver.connect()

    await driver.tap(540, 1200)
    await driver.swipe(540, 1600, 540, 400, duration_ms=300)
    await driver.input_text("hello", clear=True)
    png_bytes = await driver.screenshot()
    tree = await driver.get_ui_tree()


asyncio.run(main())
```

HTTP-only Android:

```python
import asyncio
from mobilerun_core_cli import AndroidPortalHttpDriver


async def main():
    driver = AndroidPortalHttpDriver(
        url="http://127.0.0.1:18080",
        token="...",
    )
    await driver.connect()
    await driver.tap(540, 1200)


asyncio.run(main())
```

iOS Portal:

```python
import asyncio
from mobilerun_core_cli import IOSPortalDriver


async def main():
    driver = IOSPortalDriver("http://127.0.0.1:6643")
    await driver.connect()
    await driver.start_app("com.apple.Preferences")


asyncio.run(main())
```

## 🧱 Layout

```
mobilerun_core_cli/
├── __init__.py            Re-exports the public surface
├── portal.py              Portal APK lifecycle + content-provider helpers
├── driver/
│   ├── base.py            DeviceDriver ABC, DeviceDisconnectedError
│   ├── android.py         AndroidDriver — ADB-backed concrete driver
│   ├── android_http.py    AndroidPortalHttpDriver — HTTP-only Android driver
│   └── ios.py             IOSPortalDriver — ios-portal HTTP driver
└── transport/
    └── portal_client.py   PortalClient — TCP-with-content-provider fallback
```

## 📚 Public API

Re-exported from `mobilerun_core_cli`:

| Symbol | What it is |
|---|---|
| `AndroidDriver` | ADB+Portal device driver. Async methods: `tap`, `swipe`, `input_text`, `press_button`, `start_app`, `install_app`, `screenshot`, `get_ui_tree`, `get_apps`, `list_packages`, `get_date`. |
| `AndroidPortalHttpDriver` | HTTP-only Android Portal driver. Requires `url` and bearer `token`; does not use ADB at runtime. |
| `IOSPortalDriver` / `IOSDriver` | iOS Portal HTTP driver. Requires an already-running `ios-portal` URL. |
| `DeviceDriver` | Abstract base for drivers. `supported: set[str]` declares which verbs a subclass implements. |
| `DeviceDisconnectedError` | Raised when the device drops mid-call. |
| `PortalClient` | HTTP-or-content-provider client for the on-device Portal. Used internally by `AndroidDriver`; can be constructed directly for low-level access. |
| `setup_portal(device)` | Download + install + enable the Portal APK on a device. |
| `ensure_portal_ready(device)` | Idempotent: install/upgrade Portal and enable accessibility if needed. |
| `setup_keyboard(device)` | Switch the device to the Mobilerun IME. |
| `ping_portal(device)` | Verify Portal is installed and reachable. |
| `PORTAL_PACKAGE_NAME`, `A11Y_SERVICE_NAME` | Portal identifiers. |
| `portal_content_uri(pkg, path)` | Build `content://<pkg>/<path>` URIs. |
| `portal_a11y_service(pkg)`, `portal_ime_id(pkg)` | Accessibility service / IME component names. |

`AndroidDriver` accepts:

- `serial: str | None` — ADB serial; `None` picks the only connected device.
- `use_tcp: bool = False` — when `True`, the underlying `PortalClient` port-forwards Portal's HTTP server (`localhost:N → device:8080`) and uses it instead of the content provider. Faster but requires a working forward; falls back transparently.

## 🪵 Logging

All output goes through the `"mobilerun_core_cli"` logger. Configure it yourself; the package attaches no handlers.

```python
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("mobilerun_core_cli").setLevel(logging.DEBUG)
```

## 🔗 Relationship to upstream `mobilerun`

This package owns local execution drivers. The full framework imports these drivers for CLI/agent flows; `mobilerun-core` wraps them behind a sync, backend-neutral API.

Use `mobilerun-core-cli` when you need async local drivers directly.
Use [`mobilerun`](https://github.com/droidrun/mobilerun) when you want the full LLM-agent experience, CLI/TUI, and multi-platform support out of the box.

## 📄 License

MIT — see [`LICENSE`](./LICENSE).
