autoglm-gui 1.1.0__tar.gz → 1.2.0__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.
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/.gitignore +1 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/__init__.py +5 -1
- autoglm_gui-1.2.0/AutoGLM_GUI/adb_plus/serial.py +94 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/adb_plus/version.py +81 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/api/__init__.py +8 -1
- autoglm_gui-1.2.0/AutoGLM_GUI/api/agents.py +596 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/api/devices.py +145 -164
- autoglm_gui-1.2.0/AutoGLM_GUI/api/workflows.py +70 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/device_manager.py +760 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/exceptions.py +25 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/phone_agent_manager.py +549 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/phone_agent_patches.py +146 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/schemas.py +582 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/state.py +49 -0
- autoglm_gui-1.1.0/AutoGLM_GUI/static/assets/about-Crpy4Xue.js → autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/about-PcGX7dIG.js +1 -1
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/chat-B0FKL2ne.js +124 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/dialog-BSNX0L1i.js +45 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/index-BjYIY--m.css +1 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/index-CnEYDOXp.js +11 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/index-DOt5XNhh.js +1 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/logo-Cyfm06Ym.png +0 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/assets/workflows-B1hgBC_O.js +1 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/favicon.ico +0 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/index.html +20 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/logo-192.png +0 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/static/logo-512.png +0 -0
- autoglm_gui-1.2.0/AutoGLM_GUI/workflow_manager.py +181 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/PKG-INFO +51 -6
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/README.md +50 -5
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/pyproject.toml +1 -1
- autoglm_gui-1.1.0/AutoGLM_GUI/adb_plus/serial.py +0 -35
- autoglm_gui-1.1.0/AutoGLM_GUI/api/agents.py +0 -361
- autoglm_gui-1.1.0/AutoGLM_GUI/exceptions.py +0 -7
- autoglm_gui-1.1.0/AutoGLM_GUI/schemas.py +0 -274
- autoglm_gui-1.1.0/AutoGLM_GUI/state.py +0 -28
- autoglm_gui-1.1.0/AutoGLM_GUI/static/assets/chat-DGFuSj6_.js +0 -149
- autoglm_gui-1.1.0/AutoGLM_GUI/static/assets/index-C1k5Ch1V.js +0 -10
- autoglm_gui-1.1.0/AutoGLM_GUI/static/assets/index-COYnSjzf.js +0 -1
- autoglm_gui-1.1.0/AutoGLM_GUI/static/assets/index-QX6oy21q.css +0 -1
- autoglm_gui-1.1.0/AutoGLM_GUI/static/index.html +0 -13
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/__main__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/device.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/ip.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/keyboard_installer.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/mdns.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/pair.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/qr_pair.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/screenshot.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/adb_plus/touch.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/api/control.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/api/media.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/api/version.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/config.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/config_manager.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/logger.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/platform_utils.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/scrcpy_protocol.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/scrcpy_stream.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/server.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/socketio_server.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/static/assets/worker-D6BRitjy.js +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/AutoGLM_GUI/version.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/LICENSE +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/actions/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/actions/handler.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/actions/handler_ios.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/adb/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/adb/connection.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/adb/device.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/adb/input.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/adb/screenshot.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/agent.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/agent_ios.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/apps.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/apps_harmonyos.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/apps_ios.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/i18n.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/prompts.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/prompts_en.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/prompts_zh.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/config/timing.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/device_factory.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/hdc/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/hdc/connection.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/hdc/device.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/hdc/input.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/hdc/screenshot.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/model/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/model/client.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/xctest/__init__.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/xctest/connection.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/xctest/device.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/xctest/input.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/phone_agent/xctest/screenshot.py +0 -0
- {autoglm_gui-1.1.0 → autoglm_gui-1.2.0}/scrcpy-server-v3.3.3 +0 -0
|
@@ -4,11 +4,12 @@ from .keyboard_installer import ADBKeyboardInstaller
|
|
|
4
4
|
from .screenshot import Screenshot, capture_screenshot
|
|
5
5
|
from .touch import touch_down, touch_move, touch_up
|
|
6
6
|
from .ip import get_wifi_ip
|
|
7
|
-
from .serial import get_device_serial
|
|
7
|
+
from .serial import get_device_serial, extract_serial_from_mdns
|
|
8
8
|
from .device import check_device_available
|
|
9
9
|
from .pair import pair_device
|
|
10
10
|
from .mdns import discover_mdns_devices, MdnsDevice
|
|
11
11
|
from .qr_pair import qr_pairing_manager
|
|
12
|
+
from .version import get_adb_version, supports_mdns_services
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"ADBKeyboardInstaller",
|
|
@@ -19,9 +20,12 @@ __all__ = [
|
|
|
19
20
|
"touch_up",
|
|
20
21
|
"get_wifi_ip",
|
|
21
22
|
"get_device_serial",
|
|
23
|
+
"extract_serial_from_mdns",
|
|
22
24
|
"check_device_available",
|
|
23
25
|
"pair_device",
|
|
24
26
|
"discover_mdns_devices",
|
|
25
27
|
"MdnsDevice",
|
|
26
28
|
"qr_pairing_manager",
|
|
29
|
+
"get_adb_version",
|
|
30
|
+
"supports_mdns_services",
|
|
27
31
|
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Get device serial number using ADB."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from AutoGLM_GUI.platform_utils import run_cmd_silently_sync
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def extract_serial_from_mdns(device_id: str) -> Optional[str]:
|
|
10
|
+
"""
|
|
11
|
+
Extract hardware serial number from mDNS device ID.
|
|
12
|
+
|
|
13
|
+
mDNS service names follow the pattern: adb-{serial}[-{suffix}].{service_type}
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
- "adb-243a09b7-cbCO6P._adb-tls-connect._tcp" → "243a09b7"
|
|
17
|
+
- "adb-243a09b7._adb._tcp" → "243a09b7"
|
|
18
|
+
- "adb-ABC123DEF.local" → "ABC123DEF"
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
device_id: The device ID (can be mDNS service name or regular device ID)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Extracted serial number, or None if not a valid mDNS format
|
|
25
|
+
"""
|
|
26
|
+
# Check if this is an mDNS device ID
|
|
27
|
+
mdns_indicators = [
|
|
28
|
+
"._adb-tls-connect._tcp",
|
|
29
|
+
"._adb-tls-pairing._tcp",
|
|
30
|
+
"._adb._tcp",
|
|
31
|
+
".local",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
if not any(indicator in device_id for indicator in mdns_indicators):
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
# Pattern: adb-{serial}[-{suffix}].{service_type}
|
|
38
|
+
# The serial is everything after "adb-" until the next hyphen or dot
|
|
39
|
+
# Match alphanumeric characters (not just hex)
|
|
40
|
+
pattern = r"adb-([0-9a-zA-Z]+)"
|
|
41
|
+
match = re.search(pattern, device_id)
|
|
42
|
+
|
|
43
|
+
if match:
|
|
44
|
+
serial = match.group(1)
|
|
45
|
+
# Validate serial format (alphanumeric, typically 6-16 chars)
|
|
46
|
+
if len(serial) >= 6 and serial.isalnum():
|
|
47
|
+
return serial
|
|
48
|
+
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_device_serial(device_id: str, adb_path: str = "adb") -> str | None:
|
|
53
|
+
"""
|
|
54
|
+
Get the real hardware serial number of a device.
|
|
55
|
+
|
|
56
|
+
For mDNS devices, attempts to extract serial from service name first.
|
|
57
|
+
Falls back to getprop for USB/WiFi devices or if extraction fails.
|
|
58
|
+
|
|
59
|
+
This works for both USB and WiFi connected devices,
|
|
60
|
+
returning the actual hardware serial number (ro.serialno).
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
device_id: The device ID (can be USB serial or IP:port for WiFi)
|
|
64
|
+
adb_path: Path to adb executable (default: "adb")
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The device hardware serial number, or None if failed
|
|
68
|
+
"""
|
|
69
|
+
from AutoGLM_GUI.logger import logger
|
|
70
|
+
|
|
71
|
+
# Fast path: Try mDNS extraction first
|
|
72
|
+
mdns_serial = extract_serial_from_mdns(device_id)
|
|
73
|
+
if mdns_serial:
|
|
74
|
+
logger.debug(f"Extracted serial from mDNS name: {device_id} → {mdns_serial}")
|
|
75
|
+
return mdns_serial
|
|
76
|
+
|
|
77
|
+
# Fallback: Use getprop (original behavior)
|
|
78
|
+
try:
|
|
79
|
+
# Use getprop to get the actual hardware serial number
|
|
80
|
+
# This works for both USB and WiFi connections
|
|
81
|
+
result = run_cmd_silently_sync(
|
|
82
|
+
[adb_path, "-s", device_id, "shell", "getprop", "ro.serialno"],
|
|
83
|
+
timeout=3,
|
|
84
|
+
)
|
|
85
|
+
if result.returncode == 0:
|
|
86
|
+
serial = result.stdout.strip()
|
|
87
|
+
# Filter out error messages and empty values
|
|
88
|
+
if serial and not serial.startswith("error:") and serial != "unknown":
|
|
89
|
+
logger.debug(f"Got serial via getprop: {device_id} → {serial}")
|
|
90
|
+
return serial
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.debug(f"Failed to get serial via getprop for {device_id}: {e}")
|
|
93
|
+
|
|
94
|
+
return None
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""ADB version detection and feature support checking."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from AutoGLM_GUI.logger import logger
|
|
7
|
+
from AutoGLM_GUI.platform_utils import run_cmd_silently_sync
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_adb_version(adb_path: str = "adb") -> Optional[Tuple[int, int, int]]:
|
|
11
|
+
"""
|
|
12
|
+
Get ADB version as (major, minor, patch) tuple.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
adb_path: Path to adb executable
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Version tuple or None if failed
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> get_adb_version()
|
|
22
|
+
(34, 0, 5) # ADB version 34.0.5
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
result = run_cmd_silently_sync([adb_path, "version"], timeout=3)
|
|
26
|
+
|
|
27
|
+
if result.returncode != 0:
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
# Parse "Android Debug Bridge version 1.0.41"
|
|
31
|
+
# Or "Version 34.0.5-11580240"
|
|
32
|
+
match = re.search(r"version (\d+)\.(\d+)\.(\d+)", result.stdout, re.IGNORECASE)
|
|
33
|
+
if match:
|
|
34
|
+
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
|
|
35
|
+
|
|
36
|
+
# Legacy format: "Android Debug Bridge version 1.0.XX"
|
|
37
|
+
match = re.search(r"version 1\.0\.(\d+)", result.stdout)
|
|
38
|
+
if match:
|
|
39
|
+
return (1, 0, int(match.group(1)))
|
|
40
|
+
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logger.debug(f"Failed to get ADB version: {e}")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def supports_mdns_services(adb_path: str = "adb") -> bool:
|
|
49
|
+
"""
|
|
50
|
+
Check if ADB supports 'mdns services' command.
|
|
51
|
+
|
|
52
|
+
This feature was added in ADB 30.0.0+ (Android 11 SDK Platform Tools).
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
adb_path: Path to adb executable
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
True if supported, False otherwise
|
|
59
|
+
"""
|
|
60
|
+
# Quick feature detection: try running the command
|
|
61
|
+
try:
|
|
62
|
+
result = run_cmd_silently_sync([adb_path, "mdns", "services"], timeout=5)
|
|
63
|
+
|
|
64
|
+
# If command succeeds or returns "List of discovered mdns services", it's supported
|
|
65
|
+
if result.returncode == 0 or "mdns services" in result.stdout.lower():
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
# Check for "unknown command" error
|
|
69
|
+
stderr_lower = result.stderr.lower()
|
|
70
|
+
if "unknown" in stderr_lower or "not found" in stderr_lower:
|
|
71
|
+
logger.info(
|
|
72
|
+
"ADB does not support 'mdns services' command (requires ADB 30.0.0+)"
|
|
73
|
+
)
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
# If we get here, assume not supported
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.debug(f"Failed to check mDNS support: {e}")
|
|
81
|
+
return False
|
|
@@ -13,7 +13,7 @@ from fastapi.staticfiles import StaticFiles
|
|
|
13
13
|
from AutoGLM_GUI.version import APP_VERSION
|
|
14
14
|
from AutoGLM_GUI.adb_plus.qr_pair import qr_pairing_manager
|
|
15
15
|
|
|
16
|
-
from . import agents, control, devices, media, version
|
|
16
|
+
from . import agents, control, devices, media, version, workflows
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _get_static_dir() -> Path | None:
|
|
@@ -57,6 +57,7 @@ def create_app() -> FastAPI:
|
|
|
57
57
|
app.include_router(control.router)
|
|
58
58
|
app.include_router(media.router)
|
|
59
59
|
app.include_router(version.router)
|
|
60
|
+
app.include_router(workflows.router)
|
|
60
61
|
|
|
61
62
|
@app.on_event("startup")
|
|
62
63
|
async def startup_event():
|
|
@@ -64,6 +65,12 @@ def create_app() -> FastAPI:
|
|
|
64
65
|
# Start QR pairing session cleanup task
|
|
65
66
|
asyncio.create_task(qr_pairing_manager.cleanup_expired_sessions())
|
|
66
67
|
|
|
68
|
+
# Start device polling
|
|
69
|
+
from AutoGLM_GUI.device_manager import DeviceManager
|
|
70
|
+
|
|
71
|
+
device_manager = DeviceManager.get_instance()
|
|
72
|
+
device_manager.start_polling()
|
|
73
|
+
|
|
67
74
|
static_dir = _get_static_dir()
|
|
68
75
|
if static_dir is not None and static_dir.exists():
|
|
69
76
|
assets_dir = static_dir / "assets"
|