use-computer 0.0.1__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.
- use_computer-0.0.1/.env.example +6 -0
- use_computer-0.0.1/.gitignore +9 -0
- use_computer-0.0.1/.pre-commit-config.yaml +15 -0
- use_computer-0.0.1/PKG-INFO +133 -0
- use_computer-0.0.1/README.md +111 -0
- use_computer-0.0.1/examples/ios_quickstart.py +89 -0
- use_computer-0.0.1/examples/quickstart.py +45 -0
- use_computer-0.0.1/examples/setup_with_exec.py +54 -0
- use_computer-0.0.1/examples/upload_file.py +43 -0
- use_computer-0.0.1/mmini/__init__.py +48 -0
- use_computer-0.0.1/mmini/ax_transpile.py +504 -0
- use_computer-0.0.1/mmini/client.py +362 -0
- use_computer-0.0.1/mmini/display.py +39 -0
- use_computer-0.0.1/mmini/errors.py +68 -0
- use_computer-0.0.1/mmini/ios/__init__.py +14 -0
- use_computer-0.0.1/mmini/ios/apps.py +57 -0
- use_computer-0.0.1/mmini/ios/environment.py +49 -0
- use_computer-0.0.1/mmini/ios/input.py +118 -0
- use_computer-0.0.1/mmini/macos/__init__.py +4 -0
- use_computer-0.0.1/mmini/macos/keyboard.py +59 -0
- use_computer-0.0.1/mmini/macos/mouse.py +105 -0
- use_computer-0.0.1/mmini/models.py +79 -0
- use_computer-0.0.1/mmini/parsers.py +308 -0
- use_computer-0.0.1/mmini/py.typed +1 -0
- use_computer-0.0.1/mmini/recording.py +88 -0
- use_computer-0.0.1/mmini/retry.py +135 -0
- use_computer-0.0.1/mmini/sandbox.py +419 -0
- use_computer-0.0.1/mmini/screenshot.py +63 -0
- use_computer-0.0.1/mmini/tasks/__init__.py +307 -0
- use_computer-0.0.1/mmini/tasks/templates/pre_command.sh +2 -0
- use_computer-0.0.1/mmini/tasks/templates/task.toml +18 -0
- use_computer-0.0.1/mmini/tasks/templates/test_ios.sh +20 -0
- use_computer-0.0.1/mmini/tasks/templates/test_ios_nograder.sh +4 -0
- use_computer-0.0.1/mmini/tasks/templates/test_macos.sh +10 -0
- use_computer-0.0.1/mmini/tasks/templates/test_macos_check.sh +10 -0
- use_computer-0.0.1/mmini/tasks/templates/test_macos_nograder.sh +7 -0
- use_computer-0.0.1/pyproject.toml +59 -0
- use_computer-0.0.1/use_computer/__init__.py +15 -0
- use_computer-0.0.1/use_computer/py.typed +1 -0
- use_computer-0.0.1/uv.lock +941 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.15.12
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff-format
|
|
6
|
+
- id: ruff-check
|
|
7
|
+
args: [--fix]
|
|
8
|
+
|
|
9
|
+
- repo: local
|
|
10
|
+
hooks:
|
|
11
|
+
- id: ty-check
|
|
12
|
+
name: ty check
|
|
13
|
+
entry: uv run --group dev ty check .
|
|
14
|
+
language: system
|
|
15
|
+
pass_filenames: false
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: use-computer
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Python SDK for the use.computer macOS and iOS Computer Use API
|
|
5
|
+
Project-URL: Homepage, https://use.computer
|
|
6
|
+
Project-URL: Documentation, https://github.com/josancamon19/mmini-sdk#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/josancamon19/mmini-sdk
|
|
8
|
+
Author: use.computer
|
|
9
|
+
Keywords: automation,computer-use,ios,macos,sandbox
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: httpx>=0.27
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# use-computer Python SDK
|
|
24
|
+
|
|
25
|
+
Python SDK for the use.computer macOS and iOS Computer Use API.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install use-computer
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from use_computer import Computer
|
|
37
|
+
|
|
38
|
+
client = Computer(api_key="mk_live_...")
|
|
39
|
+
sandbox = client.create()
|
|
40
|
+
|
|
41
|
+
# Screenshot
|
|
42
|
+
img = sandbox.screenshot.take_full_screen()
|
|
43
|
+
|
|
44
|
+
# Mouse
|
|
45
|
+
sandbox.mouse.click(500, 400)
|
|
46
|
+
sandbox.mouse.move(100, 200)
|
|
47
|
+
sandbox.mouse.scroll(500, 400, "down", 3)
|
|
48
|
+
sandbox.mouse.drag(100, 100, 300, 300)
|
|
49
|
+
|
|
50
|
+
# Keyboard
|
|
51
|
+
sandbox.keyboard.type("Hello")
|
|
52
|
+
sandbox.keyboard.press("enter")
|
|
53
|
+
sandbox.keyboard.hotkey("command+space")
|
|
54
|
+
|
|
55
|
+
# Display
|
|
56
|
+
info = sandbox.display.get_info()
|
|
57
|
+
windows = sandbox.display.get_windows()
|
|
58
|
+
|
|
59
|
+
# Recording
|
|
60
|
+
recording = sandbox.recording.start(name="my-recording")
|
|
61
|
+
# ... do stuff ...
|
|
62
|
+
sandbox.recording.stop(recording.id)
|
|
63
|
+
sandbox.recording.download(recording.id, "output.mp4")
|
|
64
|
+
|
|
65
|
+
# Cleanup
|
|
66
|
+
sandbox.close()
|
|
67
|
+
client.close()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Environment
|
|
71
|
+
|
|
72
|
+
`Computer()` reads these environment variables when explicit values are not passed:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
USE_COMPUTER_API_KEY=mk_live_...
|
|
76
|
+
USE_COMPUTER_BASE_URL=https://api.use.computer
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`USE_COMPUTER_BASE_URL` is optional. The default is `https://api.use.computer`.
|
|
80
|
+
|
|
81
|
+
## Async
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from use_computer import AsyncComputer
|
|
85
|
+
|
|
86
|
+
client = AsyncComputer(api_key="mk_live_...")
|
|
87
|
+
sandbox = await client.create()
|
|
88
|
+
img = await sandbox.screenshot.take_full_screen()
|
|
89
|
+
await sandbox.close()
|
|
90
|
+
await client.close()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Local Gateway
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from use_computer import Computer
|
|
97
|
+
|
|
98
|
+
client = Computer(
|
|
99
|
+
api_key="sk-local",
|
|
100
|
+
base_url="http://localhost:8080",
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Backward Compatibility
|
|
105
|
+
|
|
106
|
+
The original import path still works:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from mmini import Mmini
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
New code should prefer:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from use_computer import Computer
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Publishing
|
|
119
|
+
|
|
120
|
+
CI publishes `use-computer` from the `main` branch. The first release is
|
|
121
|
+
`0.0.1`; after that the workflow reads the latest `vX.Y.Z` tag and bumps the
|
|
122
|
+
patch version.
|
|
123
|
+
|
|
124
|
+
For CI, prefer PyPI Trusted Publishing. If using an API token instead, set a
|
|
125
|
+
repo secret named `PYPI_API_TOKEN`; do not commit tokens to `.env`.
|
|
126
|
+
|
|
127
|
+
## Development
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
uv run --group dev pre-commit install
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Pre-commit runs `ruff format`, `ruff check --fix`, and `ty check`.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# use-computer Python SDK
|
|
2
|
+
|
|
3
|
+
Python SDK for the use.computer macOS and iOS Computer Use API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install use-computer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from use_computer import Computer
|
|
15
|
+
|
|
16
|
+
client = Computer(api_key="mk_live_...")
|
|
17
|
+
sandbox = client.create()
|
|
18
|
+
|
|
19
|
+
# Screenshot
|
|
20
|
+
img = sandbox.screenshot.take_full_screen()
|
|
21
|
+
|
|
22
|
+
# Mouse
|
|
23
|
+
sandbox.mouse.click(500, 400)
|
|
24
|
+
sandbox.mouse.move(100, 200)
|
|
25
|
+
sandbox.mouse.scroll(500, 400, "down", 3)
|
|
26
|
+
sandbox.mouse.drag(100, 100, 300, 300)
|
|
27
|
+
|
|
28
|
+
# Keyboard
|
|
29
|
+
sandbox.keyboard.type("Hello")
|
|
30
|
+
sandbox.keyboard.press("enter")
|
|
31
|
+
sandbox.keyboard.hotkey("command+space")
|
|
32
|
+
|
|
33
|
+
# Display
|
|
34
|
+
info = sandbox.display.get_info()
|
|
35
|
+
windows = sandbox.display.get_windows()
|
|
36
|
+
|
|
37
|
+
# Recording
|
|
38
|
+
recording = sandbox.recording.start(name="my-recording")
|
|
39
|
+
# ... do stuff ...
|
|
40
|
+
sandbox.recording.stop(recording.id)
|
|
41
|
+
sandbox.recording.download(recording.id, "output.mp4")
|
|
42
|
+
|
|
43
|
+
# Cleanup
|
|
44
|
+
sandbox.close()
|
|
45
|
+
client.close()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Environment
|
|
49
|
+
|
|
50
|
+
`Computer()` reads these environment variables when explicit values are not passed:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
USE_COMPUTER_API_KEY=mk_live_...
|
|
54
|
+
USE_COMPUTER_BASE_URL=https://api.use.computer
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`USE_COMPUTER_BASE_URL` is optional. The default is `https://api.use.computer`.
|
|
58
|
+
|
|
59
|
+
## Async
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from use_computer import AsyncComputer
|
|
63
|
+
|
|
64
|
+
client = AsyncComputer(api_key="mk_live_...")
|
|
65
|
+
sandbox = await client.create()
|
|
66
|
+
img = await sandbox.screenshot.take_full_screen()
|
|
67
|
+
await sandbox.close()
|
|
68
|
+
await client.close()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Local Gateway
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from use_computer import Computer
|
|
75
|
+
|
|
76
|
+
client = Computer(
|
|
77
|
+
api_key="sk-local",
|
|
78
|
+
base_url="http://localhost:8080",
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Backward Compatibility
|
|
83
|
+
|
|
84
|
+
The original import path still works:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from mmini import Mmini
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
New code should prefer:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from use_computer import Computer
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Publishing
|
|
97
|
+
|
|
98
|
+
CI publishes `use-computer` from the `main` branch. The first release is
|
|
99
|
+
`0.0.1`; after that the workflow reads the latest `vX.Y.Z` tag and bumps the
|
|
100
|
+
patch version.
|
|
101
|
+
|
|
102
|
+
For CI, prefer PyPI Trusted Publishing. If using an API token instead, set a
|
|
103
|
+
repo secret named `PYPI_API_TOKEN`; do not commit tokens to `.env`.
|
|
104
|
+
|
|
105
|
+
## Development
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
uv run --group dev pre-commit install
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Pre-commit runs `ruff format`, `ruff check --fix`, and `ty check`.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
iOS simulator sandbox — end to end example.
|
|
3
|
+
|
|
4
|
+
Creates an iPhone simulator, opens Safari, takes a screenshot,
|
|
5
|
+
taps around, types a URL, and cleans up.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
cd sdk && uv run python examples/ios_quickstart.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
from use_computer import Computer
|
|
14
|
+
|
|
15
|
+
client = Computer(base_url="http://localhost:8080")
|
|
16
|
+
|
|
17
|
+
# Create an iOS sandbox (iPhone 17 Pro by default)
|
|
18
|
+
sandbox = client.create(type="ios")
|
|
19
|
+
print(f"Created: {sandbox}")
|
|
20
|
+
|
|
21
|
+
# Check display info
|
|
22
|
+
info = sandbox.display.get_info()
|
|
23
|
+
print(f"Display: {info.width}x{info.height} @{info.scale}x")
|
|
24
|
+
|
|
25
|
+
# Take initial screenshot (home screen)
|
|
26
|
+
time.sleep(3) # wait for simulator to settle
|
|
27
|
+
img = sandbox.screenshot.take_full_screen()
|
|
28
|
+
with open("ios_home.png", "wb") as f:
|
|
29
|
+
f.write(img)
|
|
30
|
+
print(f"Home screen saved ({len(img)} bytes)")
|
|
31
|
+
|
|
32
|
+
# Open Safari via URL scheme
|
|
33
|
+
sandbox.apps.open_url("https://example.com")
|
|
34
|
+
time.sleep(3)
|
|
35
|
+
|
|
36
|
+
# Screenshot Safari
|
|
37
|
+
img = sandbox.screenshot.take_full_screen()
|
|
38
|
+
with open("ios_safari.png", "wb") as f:
|
|
39
|
+
f.write(img)
|
|
40
|
+
print("Safari screenshot saved")
|
|
41
|
+
|
|
42
|
+
# Tap the address bar (top center of screen)
|
|
43
|
+
sandbox.input.tap(info.width / 2, 70)
|
|
44
|
+
time.sleep(1)
|
|
45
|
+
|
|
46
|
+
# Type a URL
|
|
47
|
+
sandbox.input.type_text("https://apple.com")
|
|
48
|
+
time.sleep(0.5)
|
|
49
|
+
|
|
50
|
+
# Press Go (tap keyboard return area)
|
|
51
|
+
sandbox.input.press_button("HOME") # dismiss keyboard first
|
|
52
|
+
time.sleep(1)
|
|
53
|
+
|
|
54
|
+
# Screenshot final state
|
|
55
|
+
img = sandbox.screenshot.take_full_screen()
|
|
56
|
+
with open("ios_final.png", "wb") as f:
|
|
57
|
+
f.write(img)
|
|
58
|
+
print("Final screenshot saved")
|
|
59
|
+
|
|
60
|
+
# Set dark mode
|
|
61
|
+
sandbox.environment.set_appearance("dark")
|
|
62
|
+
time.sleep(1)
|
|
63
|
+
img = sandbox.screenshot.take_full_screen()
|
|
64
|
+
with open("ios_dark.png", "wb") as f:
|
|
65
|
+
f.write(img)
|
|
66
|
+
print("Dark mode screenshot saved")
|
|
67
|
+
|
|
68
|
+
# Upload a file to the simulator
|
|
69
|
+
sandbox.upload_bytes(b"Hello from use.computer iOS!", "Documents/test.txt")
|
|
70
|
+
print("File uploaded")
|
|
71
|
+
|
|
72
|
+
# Download it back
|
|
73
|
+
sandbox.download_file("Documents/test.txt", "ios_downloaded.txt")
|
|
74
|
+
with open("ios_downloaded.txt") as f:
|
|
75
|
+
print(f"Downloaded: {f.read()}")
|
|
76
|
+
|
|
77
|
+
# Start recording
|
|
78
|
+
rec = sandbox.recording.start(name="demo")
|
|
79
|
+
print(f"Recording started: {rec.id}")
|
|
80
|
+
time.sleep(3)
|
|
81
|
+
|
|
82
|
+
# Stop recording
|
|
83
|
+
rec = sandbox.recording.stop(rec.id)
|
|
84
|
+
print(f"Recording stopped: {rec.status}")
|
|
85
|
+
|
|
86
|
+
# Clean up
|
|
87
|
+
sandbox.close()
|
|
88
|
+
print("Sandbox destroyed.")
|
|
89
|
+
client.close()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quick test of the use-computer SDK against a local gateway.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
cd sdk && uv run python examples/quickstart.py
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
from use_computer import Computer
|
|
11
|
+
|
|
12
|
+
client = Computer(base_url="http://localhost:8080")
|
|
13
|
+
|
|
14
|
+
sandbox = client.create()
|
|
15
|
+
print(f"Created: {sandbox}")
|
|
16
|
+
print(f"VNC: {sandbox.vnc_url}")
|
|
17
|
+
|
|
18
|
+
# Open TextEdit via exec
|
|
19
|
+
sandbox.exec_ssh("open -a TextEdit")
|
|
20
|
+
time.sleep(2)
|
|
21
|
+
|
|
22
|
+
# Click in the document area to focus it
|
|
23
|
+
sandbox.mouse.click(512, 400)
|
|
24
|
+
time.sleep(0.5)
|
|
25
|
+
|
|
26
|
+
# Take initial screenshot
|
|
27
|
+
img = sandbox.screenshot.take_full_screen()
|
|
28
|
+
with open("screen.png", "wb") as f:
|
|
29
|
+
f.write(img)
|
|
30
|
+
print(f"Screenshot saved to screen.png ({len(img)} bytes)")
|
|
31
|
+
|
|
32
|
+
# Type something
|
|
33
|
+
sandbox.keyboard.type("Hello from use.computer!")
|
|
34
|
+
time.sleep(0.5)
|
|
35
|
+
|
|
36
|
+
# Screenshot after typing
|
|
37
|
+
img = sandbox.screenshot.take_full_screen()
|
|
38
|
+
with open("screen_after.png", "wb") as f:
|
|
39
|
+
f.write(img)
|
|
40
|
+
print("After typing saved to screen_after.png")
|
|
41
|
+
|
|
42
|
+
# Clean up
|
|
43
|
+
sandbox.close()
|
|
44
|
+
print("Sandbox destroyed.")
|
|
45
|
+
client.close()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example: seed a sandbox by running shell commands via exec.
|
|
3
|
+
|
|
4
|
+
Opens Notes, creates a note, and sets system preferences — all via exec.
|
|
5
|
+
This replaces the old seed mechanism with direct shell commands.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
cd sdk && uv run python examples/setup_with_exec.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
|
|
13
|
+
from use_computer import AsyncComputer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def main() -> None:
|
|
17
|
+
client = AsyncComputer(base_url="http://localhost:8080")
|
|
18
|
+
sandbox = await client.create()
|
|
19
|
+
print(f"Created: {sandbox.sandbox_id}")
|
|
20
|
+
|
|
21
|
+
# Open an app
|
|
22
|
+
await sandbox.exec_ssh("open -a Notes")
|
|
23
|
+
await asyncio.sleep(2)
|
|
24
|
+
|
|
25
|
+
# Create a note via osascript
|
|
26
|
+
await sandbox.exec_ssh(
|
|
27
|
+
'osascript -e \'tell application "Notes" to make new note'
|
|
28
|
+
' with properties {name:"Test Note", body:"Created by mmini SDK"}\''
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Set system preferences
|
|
32
|
+
await sandbox.exec_ssh("defaults write com.apple.dock autohide -bool true && killall Dock")
|
|
33
|
+
|
|
34
|
+
# Run any shell command
|
|
35
|
+
result = await sandbox.exec_ssh("sw_vers -productVersion")
|
|
36
|
+
print(f"macOS version: {result.stdout.strip()}")
|
|
37
|
+
|
|
38
|
+
# Verify the note was created
|
|
39
|
+
notes = await sandbox.exec_ssh(
|
|
40
|
+
"osascript -e 'tell application \"Notes\" to get the name of every note'"
|
|
41
|
+
)
|
|
42
|
+
print(f"Notes: {notes.stdout.strip()}")
|
|
43
|
+
|
|
44
|
+
# Take a screenshot to see the result
|
|
45
|
+
img = await sandbox.screenshot.take_full_screen()
|
|
46
|
+
with open("setup_result.png", "wb") as f:
|
|
47
|
+
f.write(img)
|
|
48
|
+
print("Screenshot saved to setup_result.png")
|
|
49
|
+
|
|
50
|
+
await sandbox.close()
|
|
51
|
+
await client.close()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example: upload a file to a sandbox and verify it.
|
|
3
|
+
|
|
4
|
+
Uses the file upload endpoint to put a file on the VM's filesystem,
|
|
5
|
+
then verifies it exists via exec.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
cd sdk && uv run python examples/upload_file.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
|
|
13
|
+
from use_computer import AsyncComputer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def main() -> None:
|
|
17
|
+
client = AsyncComputer(base_url="http://localhost:8080")
|
|
18
|
+
sandbox = await client.create()
|
|
19
|
+
print(f"Created: {sandbox.sandbox_id}")
|
|
20
|
+
|
|
21
|
+
# Create some content
|
|
22
|
+
content = b"Name,Score\nAlice,95\nBob,87\nCharlie,92\n"
|
|
23
|
+
|
|
24
|
+
# Upload to the VM
|
|
25
|
+
await sandbox.upload_bytes(content, "/Users/lume/Desktop/scores.csv")
|
|
26
|
+
print("Uploaded scores.csv to Desktop")
|
|
27
|
+
|
|
28
|
+
# Verify it's there
|
|
29
|
+
result = await sandbox.exec_ssh("cat /Users/lume/Desktop/scores.csv")
|
|
30
|
+
print(f"File contents:\n{result.stdout}")
|
|
31
|
+
|
|
32
|
+
# Upload a script and run it
|
|
33
|
+
script = b"#!/bin/bash\necho 'Hello from uploaded script!'\nls ~/Desktop/\n"
|
|
34
|
+
await sandbox.upload_bytes(script, "/Users/lume/Desktop/check.sh")
|
|
35
|
+
await sandbox.exec_ssh("chmod +x /Users/lume/Desktop/check.sh")
|
|
36
|
+
result = await sandbox.exec_ssh("/Users/lume/Desktop/check.sh")
|
|
37
|
+
print(f"Script output:\n{result.stdout}")
|
|
38
|
+
|
|
39
|
+
await sandbox.close()
|
|
40
|
+
await client.close()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from mmini.client import AsyncMmini, Mmini, RunStatus
|
|
2
|
+
from mmini.errors import MminiError, PlatformNotSupportedError
|
|
3
|
+
from mmini.models import (
|
|
4
|
+
ActionResult,
|
|
5
|
+
ActResult,
|
|
6
|
+
CursorPosition,
|
|
7
|
+
DisplayInfo,
|
|
8
|
+
ExecResult,
|
|
9
|
+
RecordingInfo,
|
|
10
|
+
)
|
|
11
|
+
from mmini.parsers import Action, parse_pyautogui, parse_xdotool
|
|
12
|
+
from mmini.sandbox import (
|
|
13
|
+
AsyncIOSSandbox,
|
|
14
|
+
AsyncMacOSSandbox,
|
|
15
|
+
AsyncSandbox,
|
|
16
|
+
IOSSandbox,
|
|
17
|
+
MacOSSandbox,
|
|
18
|
+
Sandbox,
|
|
19
|
+
SandboxType,
|
|
20
|
+
)
|
|
21
|
+
from mmini.tasks import Task, TasksClient, TaskSummary
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"Action",
|
|
25
|
+
"ActionResult",
|
|
26
|
+
"ActResult",
|
|
27
|
+
"AsyncIOSSandbox",
|
|
28
|
+
"AsyncMacOSSandbox",
|
|
29
|
+
"AsyncMmini",
|
|
30
|
+
"AsyncSandbox",
|
|
31
|
+
"CursorPosition",
|
|
32
|
+
"DisplayInfo",
|
|
33
|
+
"ExecResult",
|
|
34
|
+
"IOSSandbox",
|
|
35
|
+
"MacOSSandbox",
|
|
36
|
+
"Mmini",
|
|
37
|
+
"MminiError",
|
|
38
|
+
"PlatformNotSupportedError",
|
|
39
|
+
"RecordingInfo",
|
|
40
|
+
"RunStatus",
|
|
41
|
+
"Sandbox",
|
|
42
|
+
"SandboxType",
|
|
43
|
+
"Task",
|
|
44
|
+
"TaskSummary",
|
|
45
|
+
"TasksClient",
|
|
46
|
+
"parse_pyautogui",
|
|
47
|
+
"parse_xdotool",
|
|
48
|
+
]
|