sleight 0.1.0a1__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.
Files changed (52) hide show
  1. sleight-0.1.0a1/.gitignore +32 -0
  2. sleight-0.1.0a1/LICENSE +21 -0
  3. sleight-0.1.0a1/PKG-INFO +158 -0
  4. sleight-0.1.0a1/README.md +129 -0
  5. sleight-0.1.0a1/docs//350/257/246/347/273/206/346/226/207/346/241/243/346/211/213/345/206/214.md +1774 -0
  6. sleight-0.1.0a1/pyproject.toml +62 -0
  7. sleight-0.1.0a1/sleight/__init__.py +138 -0
  8. sleight-0.1.0a1/sleight/_logging.py +53 -0
  9. sleight-0.1.0a1/sleight/core/__init__.py +1 -0
  10. sleight-0.1.0a1/sleight/core/_http.py +169 -0
  11. sleight-0.1.0a1/sleight/core/_redact.py +44 -0
  12. sleight-0.1.0a1/sleight/core/element.py +219 -0
  13. sleight-0.1.0a1/sleight/core/errors.py +102 -0
  14. sleight-0.1.0a1/sleight/core/human/__init__.py +64 -0
  15. sleight-0.1.0a1/sleight/core/human/curves.py +297 -0
  16. sleight-0.1.0a1/sleight/core/human/engine.py +435 -0
  17. sleight-0.1.0a1/sleight/core/human/presets.py +160 -0
  18. sleight-0.1.0a1/sleight/core/human/timing.py +185 -0
  19. sleight-0.1.0a1/sleight/core/human/wind.py +145 -0
  20. sleight-0.1.0a1/sleight/core/input.py +363 -0
  21. sleight-0.1.0a1/sleight/core/keymap.py +285 -0
  22. sleight-0.1.0a1/sleight/core/netidle.py +131 -0
  23. sleight-0.1.0a1/sleight/core/protocol.py +100 -0
  24. sleight-0.1.0a1/sleight/core/session.py +557 -0
  25. sleight-0.1.0a1/sleight/core/transport.py +360 -0
  26. sleight-0.1.0a1/sleight/core/types.py +191 -0
  27. sleight-0.1.0a1/sleight/lease/__init__.py +11 -0
  28. sleight-0.1.0a1/sleight/lease/base.py +81 -0
  29. sleight-0.1.0a1/sleight/lease/memory.py +78 -0
  30. sleight-0.1.0a1/sleight/pool.py +506 -0
  31. sleight-0.1.0a1/sleight/providers/__init__.py +14 -0
  32. sleight-0.1.0a1/sleight/providers/base.py +245 -0
  33. sleight-0.1.0a1/sleight/providers/cloakbrowser.py +490 -0
  34. sleight-0.1.0a1/sleight/providers/plain.py +115 -0
  35. sleight-0.1.0a1/sleight/py.typed +0 -0
  36. sleight-0.1.0a1/tests/__init__.py +0 -0
  37. sleight-0.1.0a1/tests/conftest.py +249 -0
  38. sleight-0.1.0a1/tests/test_engine.py +161 -0
  39. sleight-0.1.0a1/tests/test_human.py +493 -0
  40. sleight-0.1.0a1/tests/test_input.py +428 -0
  41. sleight-0.1.0a1/tests/test_integration_interaction.py +246 -0
  42. sleight-0.1.0a1/tests/test_integration_manager.py +130 -0
  43. sleight-0.1.0a1/tests/test_keymap.py +171 -0
  44. sleight-0.1.0a1/tests/test_lease_exclusivity.py +150 -0
  45. sleight-0.1.0a1/tests/test_logging.py +61 -0
  46. sleight-0.1.0a1/tests/test_netidle.py +113 -0
  47. sleight-0.1.0a1/tests/test_pool.py +101 -0
  48. sleight-0.1.0a1/tests/test_profilespec.py +86 -0
  49. sleight-0.1.0a1/tests/test_protocol_transport.py +232 -0
  50. sleight-0.1.0a1/tests/test_providers.py +545 -0
  51. sleight-0.1.0a1/tests/test_session.py +487 -0
  52. sleight-0.1.0a1/tests/test_types.py +155 -0
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+
8
+ # 虚拟环境
9
+ .venv/
10
+ venv/
11
+
12
+ # 工具缓存
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+ .coverage
17
+ htmlcov/
18
+
19
+ # 编辑器 / IDE —— 里面是开发机的绝对路径
20
+ .idea/
21
+ .vscode/
22
+
23
+ # 本机的 Claude Code 配置(.claude/settings.json 这类共享配置仍然入库)
24
+ .claude/settings.local.json
25
+
26
+ # 凭据
27
+ .env
28
+ *.pem
29
+ *.key
30
+
31
+ # scripts/plot_path.py 的输出
32
+ *.png
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sleight contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: sleight
3
+ Version: 0.1.0a1
4
+ Summary: Drive any CDP browser like a human — trajectories, typing rhythm, instance leasing.
5
+ Project-URL: Homepage, https://github.com/yuanqimanong/sleight
6
+ Project-URL: Repository, https://github.com/yuanqimanong/sleight
7
+ Project-URL: Issues, https://github.com/yuanqimanong/sleight/issues
8
+ Project-URL: Documentation, https://github.com/yuanqimanong/sleight/blob/main/docs/%E8%AF%A6%E7%BB%86%E6%96%87%E6%A1%A3%E6%89%8B%E5%86%8C.md
9
+ Author: sleight contributors
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: automation,browser,cdp,chrome-devtools-protocol,human-like
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: websocket-client>=1.9
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8; extra == 'dev'
25
+ Requires-Dist: ruff>=0.6; extra == 'dev'
26
+ Provides-Extra: redis
27
+ Requires-Dist: redis>=5; extra == 'redis'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # sleight
31
+
32
+ **Drive any CDP browser like a human.** Bezier trajectories with real hand tremor,
33
+ typing rhythm modelled on keystroke-dynamics research, and exclusive leasing for
34
+ browser instance pools.
35
+
36
+ Python ≥ 3.11 · one runtime dependency (`websocket-client`) · MIT
37
+
38
+ 📖 **[中文文档手册](docs/详细文档手册.md)** — 安装、快速开始、实战场景、CloakBrowser Manager 部署
39
+
40
+ ```bash
41
+ pip install sleight
42
+ ```
43
+
44
+ ## 30 seconds
45
+
46
+ ```python
47
+ from sleight import connect, Text
48
+
49
+ with connect("http://127.0.0.1:9222") as s: # opens its own tab, closes it on exit
50
+ s.open("https://example.com", wait=Text("Example Domain"))
51
+ print(s.title(), len(s.content()))
52
+ ```
53
+
54
+ With a browser pool that has real profiles behind it:
55
+
56
+ ```python
57
+ from sleight.providers import CloakBrowserManager
58
+
59
+ mgr = CloakBrowserManager("http://127.0.0.1:19000", token="…")
60
+
61
+ with mgr.lease() as inst: # exclusive lease, released on exit
62
+ with inst.session(human=True) as s: # every action gets a human trajectory
63
+ s.open("https://example.com")
64
+ s.click("#login")
65
+ s.type("#email", "user@example.com")
66
+ s.click("#submit", human=False) # …except this one, speed matters here
67
+ ```
68
+
69
+ Target one specific profile — by id, by name, or by tag:
70
+
71
+ ```python
72
+ with mgr.lease(instance_id="5edcc28a-…") as inst: ...
73
+ with mgr.lease(where=lambda i: i.name == "Win-US-02") as inst: ...
74
+ with mgr.lease(where=lambda i: "us" in i.tags) as inst: ...
75
+ ```
76
+
77
+ Three providers' worth of instances, one logical pool:
78
+
79
+ ```python
80
+ from sleight import Pool
81
+ from sleight.providers import CloakBrowserManager, Plain
82
+
83
+ pool = Pool([
84
+ CloakBrowserManager("http://10.0.0.1:9000", token=T1, name="hk"),
85
+ CloakBrowserManager("http://10.0.0.2:9000", token=T2, name="sg"),
86
+ Plain("http://127.0.0.1:9222", name="local"),
87
+ ])
88
+
89
+ with pool.lease(where=lambda i: "us" in i.tags) as inst:
90
+ ...
91
+ ```
92
+
93
+ ## Why this exists
94
+
95
+ Fingerprint-level anti-detection is a solved problem — CloakBrowser patches Chromium
96
+ at the source level, Camoufox patches Firefox. They fix **what the browser looks like**.
97
+ Nothing fixes **how it moves**.
98
+
99
+ - Playwright and Puppeteer teleport the mouse. `mouse.move(steps=N)` interpolates a
100
+ **straight line at constant speed** — zero jitter, zero acceleration. That is itself
101
+ a signature.
102
+ - The browser will not fill in the trajectory for you. Even with a humanize feature
103
+ enabled browser-side, an external CDP client produces **zero** `mousemove` events
104
+ between press and release. Measured, not assumed.
105
+ - The good trajectory work lives in JavaScript (`ghost-cursor`). Python ports are
106
+ thinly maintained.
107
+ - Crawlee for Python's `BrowserPool` [does not support remote browsers](https://github.com/apify/crawlee-python/issues/1743).
108
+
109
+ sleight fills exactly that gap: **Python + remote CDP + human behaviour + instance leasing.**
110
+
111
+ ## Relationship to Playwright
112
+
113
+ **Not a replacement — a complement.** sleight is a driver layer, not a framework.
114
+ It deliberately does not do iframes/OOPIF, downloads, video, tracing, or a full
115
+ locator DSL. When you need those, use Playwright.
116
+
117
+ The interesting part is that you can use both: sleight's `human` module is
118
+ [sans-io](https://sans-io.readthedocs.io/) — it emits `(method, params, sleep_after)`
119
+ tuples and never touches a socket — so it drives a Playwright `CDPSession` just as
120
+ happily as sleight's own transport.
121
+
122
+ ## What makes the motion credible
123
+
124
+ | | sleight | typical automation |
125
+ |---|---|---|
126
+ | Path shape | cubic Bezier, control points offset to one side | straight line |
127
+ | Micro-motion | WindMouse wind term (correlated tremor) | none, or white noise |
128
+ | Point count | Fitts's law — far small targets take longer | fixed `steps=N` |
129
+ | Landing | truncated Gaussian inside the box | dead centre |
130
+ | Coordinates | integers | floats used as "jitter" |
131
+ | Overshoot | past the target then back, distance-scaled | exact arrival |
132
+ | Typing | per-character events, interval by digraph class | one `insertText` |
133
+ | Scrolling | repeated small `mouseWheel` deltas | one `scrollTo` |
134
+
135
+ Parameters are not invented. They come from the
136
+ [WindMouse](https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/) physical
137
+ model, [ghost-cursor](https://github.com/Xetera/ghost-cursor)'s Fitts-law point
138
+ budgeting, and published keystroke-dynamics measurements (alternating-hand digraphs
139
+ average 114 ms, same-hand-different-finger 131 ms, same-finger slowest and most
140
+ variable).
141
+
142
+ ## Scope
143
+
144
+ **Does:** navigation and typed wait conditions · rendered-DOM reads · CSS queries ·
145
+ human mouse / keyboard / wheel · instance discovery across providers · cooperative
146
+ exclusive leasing with TTL renewal · idempotent recovery.
147
+
148
+ **Does not:** data extraction · scheduling and queues · fingerprint spoofing (that is
149
+ the browser's job) · iframe / OOPIF / Shadow DOM piercing · strict fencing · WebDriver
150
+ BiDi · Firefox.
151
+
152
+ ## Status
153
+
154
+ `0.1.0a1` — alpha, the API will move. Every release documents its breaking changes.
155
+
156
+ ## License
157
+
158
+ MIT
@@ -0,0 +1,129 @@
1
+ # sleight
2
+
3
+ **Drive any CDP browser like a human.** Bezier trajectories with real hand tremor,
4
+ typing rhythm modelled on keystroke-dynamics research, and exclusive leasing for
5
+ browser instance pools.
6
+
7
+ Python ≥ 3.11 · one runtime dependency (`websocket-client`) · MIT
8
+
9
+ 📖 **[中文文档手册](docs/详细文档手册.md)** — 安装、快速开始、实战场景、CloakBrowser Manager 部署
10
+
11
+ ```bash
12
+ pip install sleight
13
+ ```
14
+
15
+ ## 30 seconds
16
+
17
+ ```python
18
+ from sleight import connect, Text
19
+
20
+ with connect("http://127.0.0.1:9222") as s: # opens its own tab, closes it on exit
21
+ s.open("https://example.com", wait=Text("Example Domain"))
22
+ print(s.title(), len(s.content()))
23
+ ```
24
+
25
+ With a browser pool that has real profiles behind it:
26
+
27
+ ```python
28
+ from sleight.providers import CloakBrowserManager
29
+
30
+ mgr = CloakBrowserManager("http://127.0.0.1:19000", token="…")
31
+
32
+ with mgr.lease() as inst: # exclusive lease, released on exit
33
+ with inst.session(human=True) as s: # every action gets a human trajectory
34
+ s.open("https://example.com")
35
+ s.click("#login")
36
+ s.type("#email", "user@example.com")
37
+ s.click("#submit", human=False) # …except this one, speed matters here
38
+ ```
39
+
40
+ Target one specific profile — by id, by name, or by tag:
41
+
42
+ ```python
43
+ with mgr.lease(instance_id="5edcc28a-…") as inst: ...
44
+ with mgr.lease(where=lambda i: i.name == "Win-US-02") as inst: ...
45
+ with mgr.lease(where=lambda i: "us" in i.tags) as inst: ...
46
+ ```
47
+
48
+ Three providers' worth of instances, one logical pool:
49
+
50
+ ```python
51
+ from sleight import Pool
52
+ from sleight.providers import CloakBrowserManager, Plain
53
+
54
+ pool = Pool([
55
+ CloakBrowserManager("http://10.0.0.1:9000", token=T1, name="hk"),
56
+ CloakBrowserManager("http://10.0.0.2:9000", token=T2, name="sg"),
57
+ Plain("http://127.0.0.1:9222", name="local"),
58
+ ])
59
+
60
+ with pool.lease(where=lambda i: "us" in i.tags) as inst:
61
+ ...
62
+ ```
63
+
64
+ ## Why this exists
65
+
66
+ Fingerprint-level anti-detection is a solved problem — CloakBrowser patches Chromium
67
+ at the source level, Camoufox patches Firefox. They fix **what the browser looks like**.
68
+ Nothing fixes **how it moves**.
69
+
70
+ - Playwright and Puppeteer teleport the mouse. `mouse.move(steps=N)` interpolates a
71
+ **straight line at constant speed** — zero jitter, zero acceleration. That is itself
72
+ a signature.
73
+ - The browser will not fill in the trajectory for you. Even with a humanize feature
74
+ enabled browser-side, an external CDP client produces **zero** `mousemove` events
75
+ between press and release. Measured, not assumed.
76
+ - The good trajectory work lives in JavaScript (`ghost-cursor`). Python ports are
77
+ thinly maintained.
78
+ - Crawlee for Python's `BrowserPool` [does not support remote browsers](https://github.com/apify/crawlee-python/issues/1743).
79
+
80
+ sleight fills exactly that gap: **Python + remote CDP + human behaviour + instance leasing.**
81
+
82
+ ## Relationship to Playwright
83
+
84
+ **Not a replacement — a complement.** sleight is a driver layer, not a framework.
85
+ It deliberately does not do iframes/OOPIF, downloads, video, tracing, or a full
86
+ locator DSL. When you need those, use Playwright.
87
+
88
+ The interesting part is that you can use both: sleight's `human` module is
89
+ [sans-io](https://sans-io.readthedocs.io/) — it emits `(method, params, sleep_after)`
90
+ tuples and never touches a socket — so it drives a Playwright `CDPSession` just as
91
+ happily as sleight's own transport.
92
+
93
+ ## What makes the motion credible
94
+
95
+ | | sleight | typical automation |
96
+ |---|---|---|
97
+ | Path shape | cubic Bezier, control points offset to one side | straight line |
98
+ | Micro-motion | WindMouse wind term (correlated tremor) | none, or white noise |
99
+ | Point count | Fitts's law — far small targets take longer | fixed `steps=N` |
100
+ | Landing | truncated Gaussian inside the box | dead centre |
101
+ | Coordinates | integers | floats used as "jitter" |
102
+ | Overshoot | past the target then back, distance-scaled | exact arrival |
103
+ | Typing | per-character events, interval by digraph class | one `insertText` |
104
+ | Scrolling | repeated small `mouseWheel` deltas | one `scrollTo` |
105
+
106
+ Parameters are not invented. They come from the
107
+ [WindMouse](https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/) physical
108
+ model, [ghost-cursor](https://github.com/Xetera/ghost-cursor)'s Fitts-law point
109
+ budgeting, and published keystroke-dynamics measurements (alternating-hand digraphs
110
+ average 114 ms, same-hand-different-finger 131 ms, same-finger slowest and most
111
+ variable).
112
+
113
+ ## Scope
114
+
115
+ **Does:** navigation and typed wait conditions · rendered-DOM reads · CSS queries ·
116
+ human mouse / keyboard / wheel · instance discovery across providers · cooperative
117
+ exclusive leasing with TTL renewal · idempotent recovery.
118
+
119
+ **Does not:** data extraction · scheduling and queues · fingerprint spoofing (that is
120
+ the browser's job) · iframe / OOPIF / Shadow DOM piercing · strict fencing · WebDriver
121
+ BiDi · Firefox.
122
+
123
+ ## Status
124
+
125
+ `0.1.0a1` — alpha, the API will move. Every release documents its breaking changes.
126
+
127
+ ## License
128
+
129
+ MIT