mumdad 0.1.5__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.
- mumdad-0.1.5/PKG-INFO +148 -0
- mumdad-0.1.5/README.md +138 -0
- mumdad-0.1.5/pyproject.toml +26 -0
- mumdad-0.1.5/setup.cfg +4 -0
- mumdad-0.1.5/src/mum/__init__.py +8 -0
- mumdad-0.1.5/src/mum/android/__init__.py +0 -0
- mumdad-0.1.5/src/mum/android/base/__init__.py +0 -0
- mumdad-0.1.5/src/mum/android/base/adb/__init__.py +53 -0
- mumdad-0.1.5/src/mum/android/base/adb/_protocol.py +20 -0
- mumdad-0.1.5/src/mum/android/base/adb/_raw_adb.py +414 -0
- mumdad-0.1.5/src/mum/android/base/adb/coordinate.py +18 -0
- mumdad-0.1.5/src/mum/android/base/adb/disguise_client.py +177 -0
- mumdad-0.1.5/src/mum/android/base/adb/random_delay.py +18 -0
- mumdad-0.1.5/src/mum/android/base/adb/scroll.py +262 -0
- mumdad-0.1.5/src/mum/android/wechat/__init__.py +0 -0
- mumdad-0.1.5/src/mum/android/wechat/reposition.py +298 -0
- mumdad-0.1.5/src/mumdad.egg-info/PKG-INFO +148 -0
- mumdad-0.1.5/src/mumdad.egg-info/SOURCES.txt +20 -0
- mumdad-0.1.5/src/mumdad.egg-info/dependency_links.txt +1 -0
- mumdad-0.1.5/src/mumdad.egg-info/requires.txt +4 -0
- mumdad-0.1.5/src/mumdad.egg-info/top_level.txt +1 -0
- mumdad-0.1.5/tests/test_imports.py +31 -0
mumdad-0.1.5/PKG-INFO
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mumdad
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: Multi-platform disguise automation — ADB gesture disguise & WeChat scroll navigation
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy>=1.24
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
10
|
+
|
|
11
|
+
# mumdad — Multi-platform disguise automation
|
|
12
|
+
|
|
13
|
+
Android / iOS / HarmonyOS / Web disguise automation toolkit. Built for mobile APP data collection with anti-detection gestures and device-adaptive scroll navigation.
|
|
14
|
+
|
|
15
|
+
[](https://www.python.org/downloads/)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 一、项目介绍
|
|
20
|
+
|
|
21
|
+
mumdad 是一个多平台自动化伪装工具包,核心解决移动端 APP 自动化采集中的防风控和手势兼容性问题。
|
|
22
|
+
|
|
23
|
+
### 核心模块
|
|
24
|
+
|
|
25
|
+
| 模块 | 说明 |
|
|
26
|
+
|------|------|
|
|
27
|
+
| `adb` | ADB 伪装客户端 + scroll_down/up 手势翻页(Android 版本自适应) |
|
|
28
|
+
| `wechat` | 微信主界面会话列表归位(from×L 随机采样 + dHash 重试 + 冷启动兜底) |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 二、安装
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install mumdad
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
或从 GitHub:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install git+https://github.com/yuyidream/mumdad.git
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 三、核心特性
|
|
47
|
+
|
|
48
|
+
### 3.1 DisguiseAdbClient — ADB 伪装客户端
|
|
49
|
+
|
|
50
|
+
自动注入人类操作模拟,防止 APP 风控检测:
|
|
51
|
+
|
|
52
|
+
- **随机延迟**:每次操作前注入 80~350ms 随机 sleep
|
|
53
|
+
- **坐标微偏移**:tap 坐标 ±5px 随机 jitter
|
|
54
|
+
- **duration 随机化**:swipe 时长 + 0~80ms 随机
|
|
55
|
+
- **key_event 专门延迟**:BACK/HOME 键注入 80~200ms 专用延迟
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from mum.android.base.adb import DisguiseAdbClient
|
|
59
|
+
|
|
60
|
+
adb = DisguiseAdbClient("device_serial")
|
|
61
|
+
adb.click(540, 1200) # 自动注入延迟 + jitter
|
|
62
|
+
adb.swipe(540, 2000, 540, 500, duration_ms=400) # duration 自动加 0~80ms
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3.2 session_list_content_scroll_down/up — 会话列表手势翻页
|
|
66
|
+
|
|
67
|
+
基于 from×L 模型,Android 版本自适应:
|
|
68
|
+
|
|
69
|
+
| Android 版本 | L 参数 | 适用设备 |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| < 13 | [66%, 68%] | D1 (MI 8 UD, Android 10) |
|
|
72
|
+
| ≥ 13 | [51%, 53%] | D2 (HyperOS 16) / D3 (Harmony 13) |
|
|
73
|
+
|
|
74
|
+
关键约束:velocity ≤ 1.0 px/ms(防 Android fling 惯性)。
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from mum.android.base.adb import session_list_content_scroll_down, session_list_content_scroll_up
|
|
78
|
+
|
|
79
|
+
adb = DisguiseAdbClient("device_serial")
|
|
80
|
+
w, h = adb.wm_size()
|
|
81
|
+
|
|
82
|
+
# 翻下一页
|
|
83
|
+
session_list_content_scroll_down(adb, screen_w=w, screen_h=h)
|
|
84
|
+
|
|
85
|
+
# 回翻上一页
|
|
86
|
+
session_list_content_scroll_up(adb, screen_w=w, screen_h=h)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3.3 reposition_wechat_to_list_top — 微信会话列表归位
|
|
90
|
+
|
|
91
|
+
从任意 WeChat 状态归位到主界面会话列表最顶端。
|
|
92
|
+
|
|
93
|
+
**两阶段流程**:
|
|
94
|
+
1. **导航**:截图 → 层级检测 → 导航到 L1 chat_list (A/B/C)
|
|
95
|
+
2. **无限下拉锚点**:from×L 随机采样,不限次数一直下拉直到出现「最近」页面或 deadline_s 到期。期间连续 2 帧 dHash Hamming ≤ 3 且不在「最近」页面时,触发 `back_recover()` 冷启动恢复后继续。
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from mum.android.wechat.reposition import reposition_wechat_to_list_top
|
|
99
|
+
|
|
100
|
+
result = reposition_wechat_to_list_top(
|
|
101
|
+
adb, scale_w=1.0, screen_w=1080, screen_h=2248,
|
|
102
|
+
deadline_s=60.0,
|
|
103
|
+
)
|
|
104
|
+
print(f"归位: {'OK' if result.ok else 'FAIL'} ({result.reason})")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 四、目录结构
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
mumdad/
|
|
113
|
+
├── android/
|
|
114
|
+
│ ├── adb/ ← ADB 伪装 + scroll_down/up
|
|
115
|
+
│ │ ├── coordinate.py ← 坐标 jitter (±5px)
|
|
116
|
+
│ │ ├── random_delay.py ← 随机延迟 (80~350ms)
|
|
117
|
+
│ │ ├── disguise_client.py ← DisguiseAdbClient + Debug
|
|
118
|
+
│ │ ├── scroll.py ← session_list_content_scroll_down/up
|
|
119
|
+
│ │ └── _raw_adb.py ← 原生 ADB 包装器
|
|
120
|
+
│ └── wechat/
|
|
121
|
+
│ └── reposition.py ← 微信会话列表归位
|
|
122
|
+
├── docs/
|
|
123
|
+
│ └── adr/
|
|
124
|
+
│ └── disguise_android_feasibility.md ← 技术可行性评估
|
|
125
|
+
├── harmonyos/ ← 占位
|
|
126
|
+
├── ios/ ← 占位
|
|
127
|
+
├── web/ ← 占位
|
|
128
|
+
├── pyproject.toml
|
|
129
|
+
├── README.md
|
|
130
|
+
└── LICENSE
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 五、设备验证
|
|
136
|
+
|
|
137
|
+
| 设备 | Android | 分辨率 | 微信版本 | 验证结果 |
|
|
138
|
+
|------|---------|--------|----------|----------|
|
|
139
|
+
| D1 (MI 8 UD) | 10 | 1080×2248 | 8.0.71 | ✅ 10 轮 100% |
|
|
140
|
+
| D2 (25113PN0EC) | 16 | 1220×2656 | 8.0.71 | ✅ 10 轮 100% |
|
|
141
|
+
| D3 (WDY-AN00) | 13 | 720×1612 | 8.0.72 | ✅ 10 轮 100% |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 六、相关文档
|
|
146
|
+
|
|
147
|
+
- [技术可行性评估报告](docs/adr/disguise_android_feasibility.md) — 贝塞尔曲线拒绝、DisguiseAdbClient、手势参数标定
|
|
148
|
+
- [layernav_android](https://github.com/yuyidream/layernav_android) — 页面层级导航框架(本项目的冷启动依赖)
|
mumdad-0.1.5/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# mumdad — Multi-platform disguise automation
|
|
2
|
+
|
|
3
|
+
Android / iOS / HarmonyOS / Web disguise automation toolkit. Built for mobile APP data collection with anti-detection gestures and device-adaptive scroll navigation.
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 一、项目介绍
|
|
10
|
+
|
|
11
|
+
mumdad 是一个多平台自动化伪装工具包,核心解决移动端 APP 自动化采集中的防风控和手势兼容性问题。
|
|
12
|
+
|
|
13
|
+
### 核心模块
|
|
14
|
+
|
|
15
|
+
| 模块 | 说明 |
|
|
16
|
+
|------|------|
|
|
17
|
+
| `adb` | ADB 伪装客户端 + scroll_down/up 手势翻页(Android 版本自适应) |
|
|
18
|
+
| `wechat` | 微信主界面会话列表归位(from×L 随机采样 + dHash 重试 + 冷启动兜底) |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 二、安装
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install mumdad
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
或从 GitHub:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install git+https://github.com/yuyidream/mumdad.git
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 三、核心特性
|
|
37
|
+
|
|
38
|
+
### 3.1 DisguiseAdbClient — ADB 伪装客户端
|
|
39
|
+
|
|
40
|
+
自动注入人类操作模拟,防止 APP 风控检测:
|
|
41
|
+
|
|
42
|
+
- **随机延迟**:每次操作前注入 80~350ms 随机 sleep
|
|
43
|
+
- **坐标微偏移**:tap 坐标 ±5px 随机 jitter
|
|
44
|
+
- **duration 随机化**:swipe 时长 + 0~80ms 随机
|
|
45
|
+
- **key_event 专门延迟**:BACK/HOME 键注入 80~200ms 专用延迟
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from mum.android.base.adb import DisguiseAdbClient
|
|
49
|
+
|
|
50
|
+
adb = DisguiseAdbClient("device_serial")
|
|
51
|
+
adb.click(540, 1200) # 自动注入延迟 + jitter
|
|
52
|
+
adb.swipe(540, 2000, 540, 500, duration_ms=400) # duration 自动加 0~80ms
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3.2 session_list_content_scroll_down/up — 会话列表手势翻页
|
|
56
|
+
|
|
57
|
+
基于 from×L 模型,Android 版本自适应:
|
|
58
|
+
|
|
59
|
+
| Android 版本 | L 参数 | 适用设备 |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| < 13 | [66%, 68%] | D1 (MI 8 UD, Android 10) |
|
|
62
|
+
| ≥ 13 | [51%, 53%] | D2 (HyperOS 16) / D3 (Harmony 13) |
|
|
63
|
+
|
|
64
|
+
关键约束:velocity ≤ 1.0 px/ms(防 Android fling 惯性)。
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from mum.android.base.adb import session_list_content_scroll_down, session_list_content_scroll_up
|
|
68
|
+
|
|
69
|
+
adb = DisguiseAdbClient("device_serial")
|
|
70
|
+
w, h = adb.wm_size()
|
|
71
|
+
|
|
72
|
+
# 翻下一页
|
|
73
|
+
session_list_content_scroll_down(adb, screen_w=w, screen_h=h)
|
|
74
|
+
|
|
75
|
+
# 回翻上一页
|
|
76
|
+
session_list_content_scroll_up(adb, screen_w=w, screen_h=h)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3.3 reposition_wechat_to_list_top — 微信会话列表归位
|
|
80
|
+
|
|
81
|
+
从任意 WeChat 状态归位到主界面会话列表最顶端。
|
|
82
|
+
|
|
83
|
+
**两阶段流程**:
|
|
84
|
+
1. **导航**:截图 → 层级检测 → 导航到 L1 chat_list (A/B/C)
|
|
85
|
+
2. **无限下拉锚点**:from×L 随机采样,不限次数一直下拉直到出现「最近」页面或 deadline_s 到期。期间连续 2 帧 dHash Hamming ≤ 3 且不在「最近」页面时,触发 `back_recover()` 冷启动恢复后继续。
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from mum.android.wechat.reposition import reposition_wechat_to_list_top
|
|
89
|
+
|
|
90
|
+
result = reposition_wechat_to_list_top(
|
|
91
|
+
adb, scale_w=1.0, screen_w=1080, screen_h=2248,
|
|
92
|
+
deadline_s=60.0,
|
|
93
|
+
)
|
|
94
|
+
print(f"归位: {'OK' if result.ok else 'FAIL'} ({result.reason})")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 四、目录结构
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
mumdad/
|
|
103
|
+
├── android/
|
|
104
|
+
│ ├── adb/ ← ADB 伪装 + scroll_down/up
|
|
105
|
+
│ │ ├── coordinate.py ← 坐标 jitter (±5px)
|
|
106
|
+
│ │ ├── random_delay.py ← 随机延迟 (80~350ms)
|
|
107
|
+
│ │ ├── disguise_client.py ← DisguiseAdbClient + Debug
|
|
108
|
+
│ │ ├── scroll.py ← session_list_content_scroll_down/up
|
|
109
|
+
│ │ └── _raw_adb.py ← 原生 ADB 包装器
|
|
110
|
+
│ └── wechat/
|
|
111
|
+
│ └── reposition.py ← 微信会话列表归位
|
|
112
|
+
├── docs/
|
|
113
|
+
│ └── adr/
|
|
114
|
+
│ └── disguise_android_feasibility.md ← 技术可行性评估
|
|
115
|
+
├── harmonyos/ ← 占位
|
|
116
|
+
├── ios/ ← 占位
|
|
117
|
+
├── web/ ← 占位
|
|
118
|
+
├── pyproject.toml
|
|
119
|
+
├── README.md
|
|
120
|
+
└── LICENSE
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 五、设备验证
|
|
126
|
+
|
|
127
|
+
| 设备 | Android | 分辨率 | 微信版本 | 验证结果 |
|
|
128
|
+
|------|---------|--------|----------|----------|
|
|
129
|
+
| D1 (MI 8 UD) | 10 | 1080×2248 | 8.0.71 | ✅ 10 轮 100% |
|
|
130
|
+
| D2 (25113PN0EC) | 16 | 1220×2656 | 8.0.71 | ✅ 10 轮 100% |
|
|
131
|
+
| D3 (WDY-AN00) | 13 | 720×1612 | 8.0.72 | ✅ 10 轮 100% |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 六、相关文档
|
|
136
|
+
|
|
137
|
+
- [技术可行性评估报告](docs/adr/disguise_android_feasibility.md) — 贝塞尔曲线拒绝、DisguiseAdbClient、手势参数标定
|
|
138
|
+
- [layernav_android](https://github.com/yuyidream/layernav_android) — 页面层级导航框架(本项目的冷启动依赖)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mumdad"
|
|
7
|
+
version = "0.1.5"
|
|
8
|
+
description = "Multi-platform disguise automation — ADB gesture disguise & WeChat scroll navigation"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
"numpy>=1.24",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
dev = [
|
|
18
|
+
"pytest>=8.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
23
|
+
|
|
24
|
+
[tool.pytest.ini_options]
|
|
25
|
+
testpaths = ["tests"]
|
|
26
|
+
python_files = ["test_*.py"]
|
mumdad-0.1.5/setup.cfg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""mum — Multi-platform disguise automation toolkit.
|
|
2
|
+
|
|
3
|
+
- ADB gesture disguise (``DisguiseAdbClient``, ``DisguiseAdbClientDebug``)
|
|
4
|
+
- WeChat session list scroll navigation (from×L model, device-adaptive)
|
|
5
|
+
- Duration randomization (0~80ms) for anti-detection
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""mum ADB 伪装模块 — 统一对外导出。
|
|
2
|
+
|
|
3
|
+
- ``DisguiseAdbClient``(生产):自动注入随机延迟 + 坐标偏移 + duration 随机化
|
|
4
|
+
- ``DisguiseAdbClientDebug``(调试):跳过所有伪装,直接走原生 ADB
|
|
5
|
+
- ``scroll_down_base`` / ``scroll_up_base``:会话列表手势翻页
|
|
6
|
+
- ``scroll_up_reposition``:归位专用下拉
|
|
7
|
+
- ``scroll_down_note``:笔记详情页上滑
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from mum.android.base.adb.disguise_client import (
|
|
13
|
+
DisguiseAdbClient,
|
|
14
|
+
DisguiseAdbClientDebug,
|
|
15
|
+
)
|
|
16
|
+
from mum.android.base.adb._raw_adb import (
|
|
17
|
+
LOCKED_ADB_VERSION,
|
|
18
|
+
AdbClient,
|
|
19
|
+
AdbError,
|
|
20
|
+
AdbResult,
|
|
21
|
+
KEYCODE_BACK,
|
|
22
|
+
KEYCODE_HOME,
|
|
23
|
+
)
|
|
24
|
+
from mum.android.base.adb.scroll import (
|
|
25
|
+
scroll_down_base,
|
|
26
|
+
scroll_down_note,
|
|
27
|
+
scroll_up_base,
|
|
28
|
+
scroll_up_reposition,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# 向后兼容别名
|
|
32
|
+
session_list_content_scroll_down = scroll_down_base
|
|
33
|
+
session_list_content_scroll_up = scroll_up_base
|
|
34
|
+
|
|
35
|
+
RiskAdbClient = DisguiseAdbClient
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"LOCKED_ADB_VERSION",
|
|
39
|
+
"AdbClient",
|
|
40
|
+
"AdbError",
|
|
41
|
+
"AdbResult",
|
|
42
|
+
"KEYCODE_BACK",
|
|
43
|
+
"KEYCODE_HOME",
|
|
44
|
+
"DisguiseAdbClient",
|
|
45
|
+
"DisguiseAdbClientDebug",
|
|
46
|
+
"RiskAdbClient",
|
|
47
|
+
"scroll_down_base",
|
|
48
|
+
"scroll_down_note",
|
|
49
|
+
"scroll_up_base",
|
|
50
|
+
"scroll_up_reposition",
|
|
51
|
+
"session_list_content_scroll_down",
|
|
52
|
+
"session_list_content_scroll_up",
|
|
53
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Minimal ADB interface for duck-typing compatibility.
|
|
2
|
+
|
|
3
|
+
``DisguiseAdbClient`` satisfies this protocol, as does any object with
|
|
4
|
+
``swipe()`` and ``_run()`` methods.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AdbProtocol(Protocol):
|
|
13
|
+
"""Minimal ADB interface for scroll gesture functions.
|
|
14
|
+
|
|
15
|
+
Compatible with ``layernav_android._protocol.AdbProtocol``.
|
|
16
|
+
"""
|
|
17
|
+
def swipe(
|
|
18
|
+
self, x1: int, y1: int, x2: int, y2: int, duration_ms: int = 300,
|
|
19
|
+
) -> None: ...
|
|
20
|
+
def _run(self, args: list[str]) -> str: ...
|