otoro-cli 1.4.0 → 1.5.0
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.
- package/lib/screen_agent.py +102 -0
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Otoro Screen Agent — Python companion for reliable cross-platform computer use.
|
|
4
|
+
Installed alongside the Node.js CLI. Uses pyautogui for mouse/keyboard.
|
|
5
|
+
|
|
6
|
+
Usage: python screen_agent.py <action> [args...]
|
|
7
|
+
screenshot — capture screen, save to /tmp/otoro-screen.png
|
|
8
|
+
click <x> <y> — click at coordinates
|
|
9
|
+
rightclick <x> <y> — right-click
|
|
10
|
+
doubleclick <x> <y> — double-click
|
|
11
|
+
move <x> <y> — move mouse
|
|
12
|
+
type <text> — type text
|
|
13
|
+
hotkey <key1> <key2> — press key combo (e.g. hotkey ctrl s)
|
|
14
|
+
locate <image_path> — find image on screen, return coordinates
|
|
15
|
+
scroll <amount> — scroll up (positive) or down (negative)
|
|
16
|
+
info — get screen resolution and mouse position
|
|
17
|
+
"""
|
|
18
|
+
import sys
|
|
19
|
+
import json
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
try:
|
|
23
|
+
import pyautogui
|
|
24
|
+
pyautogui.FAILSAFE = True
|
|
25
|
+
pyautogui.PAUSE = 0.1
|
|
26
|
+
except ImportError:
|
|
27
|
+
print(json.dumps({"error": "pyautogui not installed. Run: pip install pyautogui"}))
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
if len(sys.argv) < 2:
|
|
31
|
+
print(json.dumps({"error": "No action specified"}))
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
action = sys.argv[1]
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
if action == "screenshot":
|
|
38
|
+
path = "/tmp/otoro-screen.png"
|
|
39
|
+
img = pyautogui.screenshot()
|
|
40
|
+
img.save(path)
|
|
41
|
+
print(json.dumps({"success": True, "path": path,
|
|
42
|
+
"size": [img.width, img.height]}))
|
|
43
|
+
|
|
44
|
+
elif action == "click":
|
|
45
|
+
x, y = int(sys.argv[2]), int(sys.argv[3])
|
|
46
|
+
pyautogui.click(x, y)
|
|
47
|
+
print(json.dumps({"success": True, "x": x, "y": y}))
|
|
48
|
+
|
|
49
|
+
elif action == "rightclick":
|
|
50
|
+
x, y = int(sys.argv[2]), int(sys.argv[3])
|
|
51
|
+
pyautogui.rightClick(x, y)
|
|
52
|
+
print(json.dumps({"success": True, "x": x, "y": y}))
|
|
53
|
+
|
|
54
|
+
elif action == "doubleclick":
|
|
55
|
+
x, y = int(sys.argv[2]), int(sys.argv[3])
|
|
56
|
+
pyautogui.doubleClick(x, y)
|
|
57
|
+
print(json.dumps({"success": True, "x": x, "y": y}))
|
|
58
|
+
|
|
59
|
+
elif action == "move":
|
|
60
|
+
x, y = int(sys.argv[2]), int(sys.argv[3])
|
|
61
|
+
pyautogui.moveTo(x, y)
|
|
62
|
+
print(json.dumps({"success": True, "x": x, "y": y}))
|
|
63
|
+
|
|
64
|
+
elif action == "type":
|
|
65
|
+
text = " ".join(sys.argv[2:])
|
|
66
|
+
pyautogui.typewrite(text, interval=0.02)
|
|
67
|
+
print(json.dumps({"success": True, "typed": len(text)}))
|
|
68
|
+
|
|
69
|
+
elif action == "hotkey":
|
|
70
|
+
keys = sys.argv[2:]
|
|
71
|
+
pyautogui.hotkey(*keys)
|
|
72
|
+
print(json.dumps({"success": True, "keys": keys}))
|
|
73
|
+
|
|
74
|
+
elif action == "scroll":
|
|
75
|
+
amount = int(sys.argv[2])
|
|
76
|
+
pyautogui.scroll(amount)
|
|
77
|
+
print(json.dumps({"success": True, "scrolled": amount}))
|
|
78
|
+
|
|
79
|
+
elif action == "info":
|
|
80
|
+
size = pyautogui.size()
|
|
81
|
+
pos = pyautogui.position()
|
|
82
|
+
print(json.dumps({"screen": [size.width, size.height],
|
|
83
|
+
"mouse": [pos.x, pos.y]}))
|
|
84
|
+
|
|
85
|
+
elif action == "locate":
|
|
86
|
+
path = sys.argv[2]
|
|
87
|
+
loc = pyautogui.locateOnScreen(path, confidence=0.8)
|
|
88
|
+
if loc:
|
|
89
|
+
center = pyautogui.center(loc)
|
|
90
|
+
print(json.dumps({"found": True, "x": center.x, "y": center.y,
|
|
91
|
+
"region": [loc.left, loc.top, loc.width, loc.height]}))
|
|
92
|
+
else:
|
|
93
|
+
print(json.dumps({"found": False}))
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
print(json.dumps({"error": f"Unknown action: {action}"}))
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(json.dumps({"error": str(e)}))
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
main()
|
package/package.json
CHANGED