ai-dev-browser 0.5.3__py3-none-any.whl
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.
- ai_dev_browser/__init__.py +110 -0
- ai_dev_browser/_cli.py +428 -0
- ai_dev_browser/_version.py +13 -0
- ai_dev_browser/cdp/__init__.py +6 -0
- ai_dev_browser/cdp/accessibility.py +668 -0
- ai_dev_browser/cdp/animation.py +494 -0
- ai_dev_browser/cdp/audits.py +1990 -0
- ai_dev_browser/cdp/autofill.py +292 -0
- ai_dev_browser/cdp/background_service.py +215 -0
- ai_dev_browser/cdp/bluetooth_emulation.py +626 -0
- ai_dev_browser/cdp/browser.py +821 -0
- ai_dev_browser/cdp/cache_storage.py +311 -0
- ai_dev_browser/cdp/cast.py +172 -0
- ai_dev_browser/cdp/console.py +107 -0
- ai_dev_browser/cdp/crash_report_context.py +55 -0
- ai_dev_browser/cdp/css.py +2710 -0
- ai_dev_browser/cdp/debugger.py +1405 -0
- ai_dev_browser/cdp/device_access.py +141 -0
- ai_dev_browser/cdp/device_orientation.py +45 -0
- ai_dev_browser/cdp/dom.py +2257 -0
- ai_dev_browser/cdp/dom_debugger.py +321 -0
- ai_dev_browser/cdp/dom_snapshot.py +876 -0
- ai_dev_browser/cdp/dom_storage.py +222 -0
- ai_dev_browser/cdp/emulation.py +1779 -0
- ai_dev_browser/cdp/event_breakpoints.py +56 -0
- ai_dev_browser/cdp/extensions.py +246 -0
- ai_dev_browser/cdp/fed_cm.py +283 -0
- ai_dev_browser/cdp/fetch.py +507 -0
- ai_dev_browser/cdp/file_system.py +115 -0
- ai_dev_browser/cdp/headless_experimental.py +115 -0
- ai_dev_browser/cdp/heap_profiler.py +401 -0
- ai_dev_browser/cdp/indexed_db.py +528 -0
- ai_dev_browser/cdp/input_.py +701 -0
- ai_dev_browser/cdp/inspector.py +95 -0
- ai_dev_browser/cdp/io.py +101 -0
- ai_dev_browser/cdp/layer_tree.py +464 -0
- ai_dev_browser/cdp/log.py +190 -0
- ai_dev_browser/cdp/media.py +313 -0
- ai_dev_browser/cdp/memory.py +305 -0
- ai_dev_browser/cdp/network.py +5317 -0
- ai_dev_browser/cdp/overlay.py +1468 -0
- ai_dev_browser/cdp/page.py +3970 -0
- ai_dev_browser/cdp/performance.py +124 -0
- ai_dev_browser/cdp/performance_timeline.py +200 -0
- ai_dev_browser/cdp/preload.py +575 -0
- ai_dev_browser/cdp/profiler.py +420 -0
- ai_dev_browser/cdp/pwa.py +278 -0
- ai_dev_browser/cdp/py.typed +0 -0
- ai_dev_browser/cdp/runtime.py +1589 -0
- ai_dev_browser/cdp/schema.py +50 -0
- ai_dev_browser/cdp/security.py +518 -0
- ai_dev_browser/cdp/service_worker.py +401 -0
- ai_dev_browser/cdp/smart_card_emulation.py +891 -0
- ai_dev_browser/cdp/storage.py +1573 -0
- ai_dev_browser/cdp/system_info.py +327 -0
- ai_dev_browser/cdp/target.py +822 -0
- ai_dev_browser/cdp/tethering.py +65 -0
- ai_dev_browser/cdp/tracing.py +377 -0
- ai_dev_browser/cdp/util.py +17 -0
- ai_dev_browser/cdp/web_audio.py +606 -0
- ai_dev_browser/cdp/web_authn.py +598 -0
- ai_dev_browser/cdp/web_mcp.py +219 -0
- ai_dev_browser/core/__init__.py +218 -0
- ai_dev_browser/core/_case.py +38 -0
- ai_dev_browser/core/_cf_template.py +84 -0
- ai_dev_browser/core/_element.py +431 -0
- ai_dev_browser/core/_tab.py +817 -0
- ai_dev_browser/core/_transport.py +362 -0
- ai_dev_browser/core/ax.py +605 -0
- ai_dev_browser/core/browser.py +323 -0
- ai_dev_browser/core/cdp.py +66 -0
- ai_dev_browser/core/chrome.py +253 -0
- ai_dev_browser/core/cloudflare.py +77 -0
- ai_dev_browser/core/config.py +95 -0
- ai_dev_browser/core/connection.py +403 -0
- ai_dev_browser/core/cookies.py +103 -0
- ai_dev_browser/core/dialog.py +165 -0
- ai_dev_browser/core/download.py +38 -0
- ai_dev_browser/core/elements.py +913 -0
- ai_dev_browser/core/human.py +612 -0
- ai_dev_browser/core/login.py +122 -0
- ai_dev_browser/core/mouse.py +140 -0
- ai_dev_browser/core/navigation.py +225 -0
- ai_dev_browser/core/overlays.py +148 -0
- ai_dev_browser/core/page.py +302 -0
- ai_dev_browser/core/port.py +465 -0
- ai_dev_browser/core/process.py +114 -0
- ai_dev_browser/core/snapshot.py +425 -0
- ai_dev_browser/core/storage.py +50 -0
- ai_dev_browser/core/tabs.py +125 -0
- ai_dev_browser/core/text_match.py +217 -0
- ai_dev_browser/core/window.py +84 -0
- ai_dev_browser/pool/__init__.py +34 -0
- ai_dev_browser/pool/job.py +140 -0
- ai_dev_browser/pool/persistence.py +154 -0
- ai_dev_browser/pool/pool.py +873 -0
- ai_dev_browser/pool/worker.py +171 -0
- ai_dev_browser/profile.py +107 -0
- ai_dev_browser/py.typed +0 -0
- ai_dev_browser/tools/__init__.py +9 -0
- ai_dev_browser/tools/_generate.py +209 -0
- ai_dev_browser/tools/browser_list.py +14 -0
- ai_dev_browser/tools/browser_start.py +14 -0
- ai_dev_browser/tools/browser_stop.py +14 -0
- ai_dev_browser/tools/cdp_send.py +14 -0
- ai_dev_browser/tools/click_by_html_id.py +14 -0
- ai_dev_browser/tools/click_by_ref.py +14 -0
- ai_dev_browser/tools/click_by_text.py +14 -0
- ai_dev_browser/tools/click_by_xpath.py +14 -0
- ai_dev_browser/tools/cloudflare_verify.py +14 -0
- ai_dev_browser/tools/cookies_list.py +14 -0
- ai_dev_browser/tools/cookies_load.py +14 -0
- ai_dev_browser/tools/cookies_save.py +14 -0
- ai_dev_browser/tools/dialog_respond.py +14 -0
- ai_dev_browser/tools/download.py +14 -0
- ai_dev_browser/tools/drag_by_ref.py +14 -0
- ai_dev_browser/tools/find_by_html_id.py +14 -0
- ai_dev_browser/tools/find_by_xpath.py +14 -0
- ai_dev_browser/tools/focus_by_ref.py +14 -0
- ai_dev_browser/tools/highlight_by_ref.py +14 -0
- ai_dev_browser/tools/hover_by_ref.py +14 -0
- ai_dev_browser/tools/html_by_ref.py +14 -0
- ai_dev_browser/tools/js_evaluate.py +14 -0
- ai_dev_browser/tools/login_interactive.py +14 -0
- ai_dev_browser/tools/mouse_click.py +14 -0
- ai_dev_browser/tools/mouse_drag.py +14 -0
- ai_dev_browser/tools/mouse_move.py +14 -0
- ai_dev_browser/tools/page_discover.py +14 -0
- ai_dev_browser/tools/page_emulate_focus.py +14 -0
- ai_dev_browser/tools/page_goto.py +14 -0
- ai_dev_browser/tools/page_html.py +14 -0
- ai_dev_browser/tools/page_info.py +14 -0
- ai_dev_browser/tools/page_reload.py +14 -0
- ai_dev_browser/tools/page_screenshot.py +14 -0
- ai_dev_browser/tools/page_scroll.py +14 -0
- ai_dev_browser/tools/page_wait_element.py +14 -0
- ai_dev_browser/tools/page_wait_ready.py +14 -0
- ai_dev_browser/tools/page_wait_url.py +14 -0
- ai_dev_browser/tools/screenshot_by_ref.py +14 -0
- ai_dev_browser/tools/select_by_ref.py +14 -0
- ai_dev_browser/tools/storage_get.py +14 -0
- ai_dev_browser/tools/storage_set.py +14 -0
- ai_dev_browser/tools/tab_close.py +14 -0
- ai_dev_browser/tools/tab_list.py +14 -0
- ai_dev_browser/tools/tab_new.py +14 -0
- ai_dev_browser/tools/tab_switch.py +14 -0
- ai_dev_browser/tools/type_by_ref.py +14 -0
- ai_dev_browser/tools/type_by_text.py +14 -0
- ai_dev_browser/tools/upload_by_ref.py +14 -0
- ai_dev_browser/tools/window_set.py +14 -0
- ai_dev_browser-0.5.3.dist-info/METADATA +177 -0
- ai_dev_browser-0.5.3.dist-info/RECORD +155 -0
- ai_dev_browser-0.5.3.dist-info/WHEEL +5 -0
- ai_dev_browser-0.5.3.dist-info/licenses/LICENSE +25 -0
- ai_dev_browser-0.5.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# DO NOT EDIT THIS FILE!
|
|
2
|
+
#
|
|
3
|
+
# This file is generated from the CDP specification. If you need to make
|
|
4
|
+
# changes, edit the generator and regenerate all of the modules.
|
|
5
|
+
#
|
|
6
|
+
# CDP domain: WebMCP (experimental)
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
import enum
|
|
10
|
+
import typing
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from .util import event_class, T_JSON_DICT
|
|
13
|
+
|
|
14
|
+
from . import dom
|
|
15
|
+
from . import page
|
|
16
|
+
from . import runtime
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class Annotation:
|
|
21
|
+
'''
|
|
22
|
+
Tool annotations
|
|
23
|
+
'''
|
|
24
|
+
#: A hint indicating that the tool does not modify any state.
|
|
25
|
+
read_only: typing.Optional[bool] = None
|
|
26
|
+
|
|
27
|
+
#: If the declarative tool was declared with the autosubmit attribute.
|
|
28
|
+
autosubmit: typing.Optional[bool] = None
|
|
29
|
+
|
|
30
|
+
def to_json(self) -> T_JSON_DICT:
|
|
31
|
+
json: T_JSON_DICT = dict()
|
|
32
|
+
if self.read_only is not None:
|
|
33
|
+
json['readOnly'] = self.read_only
|
|
34
|
+
if self.autosubmit is not None:
|
|
35
|
+
json['autosubmit'] = self.autosubmit
|
|
36
|
+
return json
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_json(cls, json: T_JSON_DICT) -> Annotation:
|
|
40
|
+
return cls(
|
|
41
|
+
read_only=bool(json['readOnly']) if json.get('readOnly', None) is not None else None,
|
|
42
|
+
autosubmit=bool(json['autosubmit']) if json.get('autosubmit', None) is not None else None,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class InvocationStatus(enum.Enum):
|
|
47
|
+
'''
|
|
48
|
+
Represents the status of a tool invocation.
|
|
49
|
+
'''
|
|
50
|
+
SUCCESS = "Success"
|
|
51
|
+
CANCELED = "Canceled"
|
|
52
|
+
ERROR = "Error"
|
|
53
|
+
|
|
54
|
+
def to_json(self) -> str:
|
|
55
|
+
return self.value
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_json(cls, json: str) -> InvocationStatus:
|
|
59
|
+
return cls(json)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class Tool:
|
|
64
|
+
'''
|
|
65
|
+
Definition of a tool that can be invoked.
|
|
66
|
+
'''
|
|
67
|
+
#: Tool name.
|
|
68
|
+
name: str
|
|
69
|
+
|
|
70
|
+
#: Tool description.
|
|
71
|
+
description: str
|
|
72
|
+
|
|
73
|
+
#: Frame identifier associated with the tool registration.
|
|
74
|
+
frame_id: page.FrameId
|
|
75
|
+
|
|
76
|
+
#: Schema for the tool's input parameters.
|
|
77
|
+
input_schema: typing.Optional[dict] = None
|
|
78
|
+
|
|
79
|
+
#: Optional annotations for the tool.
|
|
80
|
+
annotations: typing.Optional[Annotation] = None
|
|
81
|
+
|
|
82
|
+
#: Optional node ID for declarative tools.
|
|
83
|
+
backend_node_id: typing.Optional[dom.BackendNodeId] = None
|
|
84
|
+
|
|
85
|
+
#: The stack trace at the time of the registration.
|
|
86
|
+
stack_trace: typing.Optional[runtime.StackTrace] = None
|
|
87
|
+
|
|
88
|
+
def to_json(self) -> T_JSON_DICT:
|
|
89
|
+
json: T_JSON_DICT = dict()
|
|
90
|
+
json['name'] = self.name
|
|
91
|
+
json['description'] = self.description
|
|
92
|
+
json['frameId'] = self.frame_id.to_json()
|
|
93
|
+
if self.input_schema is not None:
|
|
94
|
+
json['inputSchema'] = self.input_schema
|
|
95
|
+
if self.annotations is not None:
|
|
96
|
+
json['annotations'] = self.annotations.to_json()
|
|
97
|
+
if self.backend_node_id is not None:
|
|
98
|
+
json['backendNodeId'] = self.backend_node_id.to_json()
|
|
99
|
+
if self.stack_trace is not None:
|
|
100
|
+
json['stackTrace'] = self.stack_trace.to_json()
|
|
101
|
+
return json
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_json(cls, json: T_JSON_DICT) -> Tool:
|
|
105
|
+
return cls(
|
|
106
|
+
name=str(json['name']),
|
|
107
|
+
description=str(json['description']),
|
|
108
|
+
frame_id=page.FrameId.from_json(json['frameId']),
|
|
109
|
+
input_schema=dict(json['inputSchema']) if json.get('inputSchema', None) is not None else None,
|
|
110
|
+
annotations=Annotation.from_json(json['annotations']) if json.get('annotations', None) is not None else None,
|
|
111
|
+
backend_node_id=dom.BackendNodeId.from_json(json['backendNodeId']) if json.get('backendNodeId', None) is not None else None,
|
|
112
|
+
stack_trace=runtime.StackTrace.from_json(json['stackTrace']) if json.get('stackTrace', None) is not None else None,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def enable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
|
|
117
|
+
'''
|
|
118
|
+
Enables the WebMCP domain, allowing events to be sent. Enabling the domain will trigger a toolsAdded event for
|
|
119
|
+
all currently registered tools.
|
|
120
|
+
'''
|
|
121
|
+
cmd_dict: T_JSON_DICT = {
|
|
122
|
+
'method': 'WebMCP.enable',
|
|
123
|
+
}
|
|
124
|
+
json = yield cmd_dict
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def disable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
|
|
128
|
+
'''
|
|
129
|
+
Disables the WebMCP domain.
|
|
130
|
+
'''
|
|
131
|
+
cmd_dict: T_JSON_DICT = {
|
|
132
|
+
'method': 'WebMCP.disable',
|
|
133
|
+
}
|
|
134
|
+
json = yield cmd_dict
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@event_class('WebMCP.toolsAdded')
|
|
138
|
+
@dataclass
|
|
139
|
+
class ToolsAdded:
|
|
140
|
+
'''
|
|
141
|
+
Event fired when new tools are added.
|
|
142
|
+
'''
|
|
143
|
+
#: Array of tools that were added.
|
|
144
|
+
tools: typing.List[Tool]
|
|
145
|
+
|
|
146
|
+
@classmethod
|
|
147
|
+
def from_json(cls, json: T_JSON_DICT) -> ToolsAdded:
|
|
148
|
+
return cls(
|
|
149
|
+
tools=[Tool.from_json(i) for i in json['tools']]
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@event_class('WebMCP.toolsRemoved')
|
|
154
|
+
@dataclass
|
|
155
|
+
class ToolsRemoved:
|
|
156
|
+
'''
|
|
157
|
+
Event fired when tools are removed.
|
|
158
|
+
'''
|
|
159
|
+
#: Array of tools that were removed.
|
|
160
|
+
tools: typing.List[Tool]
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def from_json(cls, json: T_JSON_DICT) -> ToolsRemoved:
|
|
164
|
+
return cls(
|
|
165
|
+
tools=[Tool.from_json(i) for i in json['tools']]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@event_class('WebMCP.toolInvoked')
|
|
170
|
+
@dataclass
|
|
171
|
+
class ToolInvoked:
|
|
172
|
+
'''
|
|
173
|
+
Event fired when a tool invocation starts.
|
|
174
|
+
'''
|
|
175
|
+
#: Name of the tool to invoke.
|
|
176
|
+
tool_name: str
|
|
177
|
+
#: Frame id
|
|
178
|
+
frame_id: page.FrameId
|
|
179
|
+
#: Invocation identifier.
|
|
180
|
+
invocation_id: str
|
|
181
|
+
#: The input parameters used for the invocation.
|
|
182
|
+
input_: str
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def from_json(cls, json: T_JSON_DICT) -> ToolInvoked:
|
|
186
|
+
return cls(
|
|
187
|
+
tool_name=str(json['toolName']),
|
|
188
|
+
frame_id=page.FrameId.from_json(json['frameId']),
|
|
189
|
+
invocation_id=str(json['invocationId']),
|
|
190
|
+
input_=str(json['input'])
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@event_class('WebMCP.toolResponded')
|
|
195
|
+
@dataclass
|
|
196
|
+
class ToolResponded:
|
|
197
|
+
'''
|
|
198
|
+
Event fired when a tool invocation completes or fails.
|
|
199
|
+
'''
|
|
200
|
+
#: Invocation identifier.
|
|
201
|
+
invocation_id: str
|
|
202
|
+
#: Status of the invocation.
|
|
203
|
+
status: InvocationStatus
|
|
204
|
+
#: Output or error delivered as delivered to the agent. Missing if ``status`` is anything other than Success.
|
|
205
|
+
output: typing.Optional[typing.Any]
|
|
206
|
+
#: Error text for protocol users.
|
|
207
|
+
error_text: typing.Optional[str]
|
|
208
|
+
#: The exception object, if the javascript tool threw an error>
|
|
209
|
+
exception: typing.Optional[runtime.RemoteObject]
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
def from_json(cls, json: T_JSON_DICT) -> ToolResponded:
|
|
213
|
+
return cls(
|
|
214
|
+
invocation_id=str(json['invocationId']),
|
|
215
|
+
status=InvocationStatus.from_json(json['status']),
|
|
216
|
+
output=json['output'] if json.get('output', None) is not None else None,
|
|
217
|
+
error_text=str(json['errorText']) if json.get('errorText', None) is not None else None,
|
|
218
|
+
exception=runtime.RemoteObject.from_json(json['exception']) if json.get('exception', None) is not None else None
|
|
219
|
+
)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""Core browser operations - shared by tools/ and Python package.
|
|
2
|
+
|
|
3
|
+
This module provides async functions for common browser operations.
|
|
4
|
+
Both CLI tools and Python code can use these functions.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from ai_dev_browser.core import page_goto, click_by_text, page_discover
|
|
8
|
+
|
|
9
|
+
# In async context
|
|
10
|
+
await page_goto(tab, "https://example.com")
|
|
11
|
+
await click_by_text(tab, text="Sign in")
|
|
12
|
+
result = await page_discover(tab, interactable_only=True)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# Accessibility tree interactions
|
|
16
|
+
# CDP
|
|
17
|
+
# Config (shared constants)
|
|
18
|
+
from .ax import (
|
|
19
|
+
click_by_ref,
|
|
20
|
+
drag_by_ref,
|
|
21
|
+
focus_by_ref,
|
|
22
|
+
highlight_by_ref,
|
|
23
|
+
hover_by_ref,
|
|
24
|
+
html_by_ref,
|
|
25
|
+
screenshot_by_ref,
|
|
26
|
+
select_by_ref,
|
|
27
|
+
type_by_ref,
|
|
28
|
+
upload_by_ref,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Browser lifecycle
|
|
32
|
+
from .browser import browser_list, browser_start, browser_stop
|
|
33
|
+
from .cdp import cdp_send
|
|
34
|
+
|
|
35
|
+
# Chrome detection and launching
|
|
36
|
+
from .chrome import find_chrome, launch_chrome
|
|
37
|
+
|
|
38
|
+
# Cloudflare
|
|
39
|
+
from .cloudflare import cloudflare_verify
|
|
40
|
+
from .config import (
|
|
41
|
+
DEFAULT_BASE_DIR,
|
|
42
|
+
DEFAULT_COOKIES_DIR,
|
|
43
|
+
DEFAULT_COOKIES_FILE,
|
|
44
|
+
DEFAULT_DEBUG_HOST,
|
|
45
|
+
DEFAULT_DEBUG_PORT,
|
|
46
|
+
DEFAULT_PORT_RANGE,
|
|
47
|
+
DEFAULT_PROFILE_DIR,
|
|
48
|
+
DEFAULT_PROFILE_PREFIX,
|
|
49
|
+
DEFAULT_REUSE_STRATEGY,
|
|
50
|
+
ReuseStrategy,
|
|
51
|
+
get_workspace_profile_dir,
|
|
52
|
+
get_workspace_slug,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Connection
|
|
56
|
+
from .connection import connect_browser, get_active_tab, graceful_close_browser
|
|
57
|
+
|
|
58
|
+
# Cookies
|
|
59
|
+
from .cookies import cookies_list, cookies_load, cookies_save
|
|
60
|
+
|
|
61
|
+
# Dialog (only tool-facing function)
|
|
62
|
+
from .dialog import dialog_respond
|
|
63
|
+
|
|
64
|
+
# Download
|
|
65
|
+
from .download import download
|
|
66
|
+
|
|
67
|
+
# Login (human-in-the-loop)
|
|
68
|
+
from .login import login_interactive
|
|
69
|
+
|
|
70
|
+
# Elements (only tool-facing functions)
|
|
71
|
+
from .elements import (
|
|
72
|
+
click_by_html_id,
|
|
73
|
+
click_by_text,
|
|
74
|
+
click_by_xpath,
|
|
75
|
+
find_by_html_id,
|
|
76
|
+
find_by_xpath,
|
|
77
|
+
page_scroll,
|
|
78
|
+
page_wait_element,
|
|
79
|
+
type_by_text,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Mouse
|
|
83
|
+
from .mouse import mouse_click, mouse_drag, mouse_move
|
|
84
|
+
|
|
85
|
+
# Navigation (only tool-facing functions)
|
|
86
|
+
from .navigation import (
|
|
87
|
+
page_goto,
|
|
88
|
+
page_reload,
|
|
89
|
+
page_wait_ready,
|
|
90
|
+
page_wait_url,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Page info
|
|
94
|
+
from .page import page_html, page_info, js_evaluate, page_screenshot
|
|
95
|
+
|
|
96
|
+
# Port management
|
|
97
|
+
from .port import (
|
|
98
|
+
find_debug_chromes,
|
|
99
|
+
find_workspace_chromes,
|
|
100
|
+
get_available_port,
|
|
101
|
+
is_port_in_use,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Process management
|
|
105
|
+
from .process import get_pid_on_port
|
|
106
|
+
|
|
107
|
+
# Text matching (only the dataclass is public)
|
|
108
|
+
from .text_match import MatchResult
|
|
109
|
+
|
|
110
|
+
# Snapshot (AI-friendly accessibility tree) - only tool-facing function
|
|
111
|
+
from .snapshot import page_discover
|
|
112
|
+
|
|
113
|
+
# Storage
|
|
114
|
+
from .storage import storage_get, storage_set
|
|
115
|
+
|
|
116
|
+
# Tabs
|
|
117
|
+
from .tabs import tab_close, tab_list, tab_new, tab_switch
|
|
118
|
+
|
|
119
|
+
# Window
|
|
120
|
+
from .window import page_emulate_focus, window_set
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
__all__ = [
|
|
124
|
+
# Accessibility tree interactions (by ref)
|
|
125
|
+
"click_by_ref",
|
|
126
|
+
"drag_by_ref",
|
|
127
|
+
"focus_by_ref",
|
|
128
|
+
"highlight_by_ref",
|
|
129
|
+
"hover_by_ref",
|
|
130
|
+
"html_by_ref",
|
|
131
|
+
"screenshot_by_ref",
|
|
132
|
+
"select_by_ref",
|
|
133
|
+
"type_by_ref",
|
|
134
|
+
"upload_by_ref",
|
|
135
|
+
# Browser lifecycle
|
|
136
|
+
"browser_start",
|
|
137
|
+
"browser_stop",
|
|
138
|
+
"browser_list",
|
|
139
|
+
# Config
|
|
140
|
+
"DEFAULT_BASE_DIR",
|
|
141
|
+
"DEFAULT_PROFILE_DIR",
|
|
142
|
+
"DEFAULT_COOKIES_FILE",
|
|
143
|
+
"DEFAULT_COOKIES_DIR",
|
|
144
|
+
"DEFAULT_PROFILE_PREFIX",
|
|
145
|
+
"DEFAULT_DEBUG_HOST",
|
|
146
|
+
"DEFAULT_DEBUG_PORT",
|
|
147
|
+
"DEFAULT_PORT_RANGE",
|
|
148
|
+
"DEFAULT_REUSE_STRATEGY",
|
|
149
|
+
"ReuseStrategy",
|
|
150
|
+
"get_workspace_slug",
|
|
151
|
+
"get_workspace_profile_dir",
|
|
152
|
+
# Chrome
|
|
153
|
+
"find_chrome",
|
|
154
|
+
"launch_chrome",
|
|
155
|
+
# Cloudflare
|
|
156
|
+
"cloudflare_verify",
|
|
157
|
+
# CDP
|
|
158
|
+
"cdp_send",
|
|
159
|
+
# Port
|
|
160
|
+
"is_port_in_use",
|
|
161
|
+
"find_debug_chromes",
|
|
162
|
+
"find_workspace_chromes",
|
|
163
|
+
"get_available_port",
|
|
164
|
+
# Process
|
|
165
|
+
"get_pid_on_port",
|
|
166
|
+
# Connection
|
|
167
|
+
"connect_browser",
|
|
168
|
+
"get_active_tab",
|
|
169
|
+
"graceful_close_browser",
|
|
170
|
+
# Navigation
|
|
171
|
+
"page_goto",
|
|
172
|
+
"page_reload",
|
|
173
|
+
"page_wait_ready",
|
|
174
|
+
"page_wait_url",
|
|
175
|
+
# Elements
|
|
176
|
+
"click_by_text",
|
|
177
|
+
"type_by_text",
|
|
178
|
+
"page_scroll",
|
|
179
|
+
"page_wait_element",
|
|
180
|
+
"find_by_html_id",
|
|
181
|
+
"click_by_html_id",
|
|
182
|
+
"find_by_xpath",
|
|
183
|
+
"click_by_xpath",
|
|
184
|
+
# Text matching
|
|
185
|
+
"MatchResult",
|
|
186
|
+
# Snapshot
|
|
187
|
+
"page_discover",
|
|
188
|
+
# Tabs
|
|
189
|
+
"tab_new",
|
|
190
|
+
"tab_list",
|
|
191
|
+
"tab_switch",
|
|
192
|
+
"tab_close",
|
|
193
|
+
# Page
|
|
194
|
+
"page_info",
|
|
195
|
+
"page_html",
|
|
196
|
+
"js_evaluate",
|
|
197
|
+
"page_screenshot",
|
|
198
|
+
# Mouse
|
|
199
|
+
"mouse_move",
|
|
200
|
+
"mouse_click",
|
|
201
|
+
"mouse_drag",
|
|
202
|
+
# Window
|
|
203
|
+
"window_set",
|
|
204
|
+
"page_emulate_focus",
|
|
205
|
+
# Storage
|
|
206
|
+
"storage_get",
|
|
207
|
+
"storage_set",
|
|
208
|
+
# Download
|
|
209
|
+
"download",
|
|
210
|
+
# Dialog
|
|
211
|
+
"dialog_respond",
|
|
212
|
+
# Login
|
|
213
|
+
"login_interactive",
|
|
214
|
+
# Cookies
|
|
215
|
+
"cookies_load",
|
|
216
|
+
"cookies_save",
|
|
217
|
+
"cookies_list",
|
|
218
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Case conversion utilities — single source of truth.
|
|
2
|
+
|
|
3
|
+
CDP wire format uses camelCase (`allowUnsafeEvalBlockedByCSP`); the vendored
|
|
4
|
+
cdp-python module exposes snake_case kwargs (`allow_unsafe_eval_blocked_by_csp`).
|
|
5
|
+
Anywhere we bridge the two we use one tested function so acronym handling stays
|
|
6
|
+
consistent.
|
|
7
|
+
|
|
8
|
+
The naive `re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()` shipped before this
|
|
9
|
+
module mishandled trailing/embedded acronyms — `...ByCSP` became
|
|
10
|
+
`..._by_c_s_p` and `getHTML` became `get_h_t_m_l`. Those names don't exist in
|
|
11
|
+
cdp-python, so every CDP command carrying an acronym parameter raised TypeError
|
|
12
|
+
on the retry path of `_transport.send_raw`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import re
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Two-pass regex handling acronym boundaries:
|
|
19
|
+
# 1. lower/digit → Upper ("userAgent" → "user_Agent")
|
|
20
|
+
# 2. acronym end → next word ("CSPNext", "XMLHttp" → "CSP_Next", "XML_Http")
|
|
21
|
+
# Then lowercase. Order matters: pass 1 splits the easy cases first so pass 2
|
|
22
|
+
# only has to handle runs of uppercase that precede a capitalized word.
|
|
23
|
+
_LOWER_UPPER = re.compile(r"([a-z0-9])([A-Z])")
|
|
24
|
+
_ACRONYM_WORD = re.compile(r"([A-Z]+)([A-Z][a-z])")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def camel_to_snake(name: str) -> str:
|
|
28
|
+
"""Convert a camelCase / PascalCase identifier to snake_case.
|
|
29
|
+
|
|
30
|
+
Handles trailing acronyms (`...ByCSP` → `..._by_csp`), embedded acronyms
|
|
31
|
+
(`XMLHttpRequest` → `xml_http_request`), all-caps (`URL` → `url`), digits
|
|
32
|
+
(`ipv4Address` → `ipv4_address`), and identifiers already in snake_case.
|
|
33
|
+
|
|
34
|
+
Empty string returns empty string.
|
|
35
|
+
"""
|
|
36
|
+
s = _LOWER_UPPER.sub(r"\1_\2", name)
|
|
37
|
+
s = _ACRONYM_WORD.sub(r"\1_\2", s)
|
|
38
|
+
return s.lower()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Cloudflare checkbox template image for verify_cf()."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
|
|
5
|
+
_CF_TEMPLATE_B64 = (
|
|
6
|
+
"iVBORw0KGgoAAAANSUhEUgAAAG8AAABJCAYAAAAzMHhLAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
|
|
7
|
+
"jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA/VSURBVHhe7VxprFXVGV13nt/Ae4BgCdICohFD"
|
|
8
|
+
"baWRoSCGQUXBNO2v1tbWiDRpqwVq0tRawCgVE3809p9BpaaWxqGoJQ7RggM4ULFoFKwgw5NBgTfc"
|
|
9
|
+
"eexa+9z9uIBM9T77bt9Zujnn7Hl/a3/f/vY5+z5PhcCXiOMb81SvJ8VJCxQZvExnEDwF51oJONcT"
|
|
10
|
+
"nvWPyqhCHyoqZ+KUr8wQMv9WayNyDHpieRbxeJRa5q3fKVbhM2/yzKNc/pLS+exzagiW+cxyFT4r"
|
|
11
|
+
"xWdiVb7abEk3XhSZXelBxZmxlvlfEUWP2ikhkGek14eCLgFfb/9Upk/IK7PjHo+HAqqYe7/fj0Kh"
|
|
12
|
+
"gECgKsi6QN23QxH0LNQOTzhVHuFoXK9gDU6Wt/pczWyF56neVKoV2Geb52i9VRyfX//0lhHJaody"
|
|
13
|
+
"7J2cx9Zj7utNniXM53Pmmou+w5diNjOZjCHV6/UiFApVY118UfQpedLAUqmEgwcPIhgMGgJzOa0l"
|
|
14
|
+
"LuqBupMnwgSteSJO2tbR0YFBgwaZeK1/LuqDPtU8kae1b9euXRgxYoTRPBf1w5dC3ocffohRo0b1"
|
|
15
|
+
"aqWL+qDu5Kk6mcza++3bt2P06NGGTJvm4oujz8iTlmm9E/bs2YOhQ4ea5zo3N6BRuwN10WBwyWtg"
|
|
16
|
+
"uOQ1MFzyGhgueQ0Ml7wGhkteA8Mlr4HhktfAcMlrYLjkNTBc8hoYLnkNDJe8BoZLXgOj333PU7q+"
|
|
17
|
+
"vvf09CAej5szL6orm83isccew9atW1EsFk1Q/PEfd22bJ4PKRCIRU78ORU2ePBnz5s3rLaezpTrt"
|
|
18
|
+
"Fg6H0dnZidbWVlMmn8+btvRBORqNmjz2eKPKKE11qtypoDK2Hh3GUl3d3d1IJBKmDxqXoHGrTV0V"
|
|
19
|
+
"p7rb2trM+VeLfkee8qiD9qCSBqlBrF+/3gQJTXkU1I6tT/eKE8mngtIlMAlZ+SW4WbNmYfbs2SY+"
|
|
20
|
+
"nU6bfLq3B4VrDwzrXn0S8SovqI5YLGaIqRXu50Fj0fFH5VU9giVKbWvC6qq6Fa98alvjVP5a+fU7"
|
|
21
|
+
"8tTZVCplZqI6K2Gr3IoVK7B3716sXLnSDF5B8cpj21JQ+dPB5t+3bx+WL1+O9vZ2LFmy5BhBWeHa"
|
|
22
|
+
"PjQ1NRkBS2s1gXQVabpKg1SfyonUU0GESItEtuqzdUq77ITSvWSoPuhe9aqcjlDaU3jCqW3M/wga"
|
|
23
|
+
"gKBO616D6urqMrNSQtTANRilSdgiUlcNVsScKtRCE0qQedRksWdLlU+EqA3VrXZVtxWmJdVqhtKV"
|
|
24
|
+
"T9p6OogUQeXU5+bmZkOgyqpuq/maMLpXP9SWytn+WvQ78iQ8O7slRHVag5M5ElkKtWRYYWuAGrzN"
|
|
25
|
+
"c7Kg/ILVFglNZRWvNnSVYO3ksG0oTf1Qf5SmtqzAJWhpk637VFAdmijKr3Iqb7U1mUyaq+pX3YrX"
|
|
26
|
+
"RNVV8jjeJPc78tRBCUiCkPCsGdO9hKyrTRd0rzgr8DOBzS+ojOoSSdIePatNXTXz7fojsqVh6oMs"
|
|
27
|
+
"gcqICKXpuaWlxRByOogs22fVJ6guESeTaNvV0qH6LGFqX+Vq0S/NpoQigViyrElU5yVkQc9KO1tY"
|
|
28
|
+
"Aais6pKgJFCruTbYtqQlEujhw4fNs/qmq8qrjNJ2795t6pRJPx1URkEapTVcxGnS2HqlZSJNxMrT"
|
|
29
|
+
"lcYJkofaqkW/I08DkfAkHM02BcEOToOtnYF6ljB0PTOUOZsdk6lQYVWhSBgBCq1UcUgxbfA//dSO"
|
|
30
|
+
"Oo5cqhtrHnkYK+9ZgRiF2pWiE8X8QTktXWksXbocTz2zFoc7D8FXplYzqJ2KRz/RklfoiFk/24pz"
|
|
31
|
+
"MqRSGXQfPoQbfvR9/PWJJ5EvlzCoOYqdO7ZjzIUX4/JZc7HhHy+rAAtz0rJPqBSQSXebehza2H/n"
|
|
32
|
+
"of9AxNmZKLsvDRM5ihNp1txZ2LhaQk8OaW0ZPr/ycp0kWRVpGMWQLVDbfDTRvFd7SvfKZBWzCHkr"
|
|
33
|
+
"+M6VM/HAH+/Hrr2H4GG/NKU6s1zvMhVsfuMdTLh0AiIJbh/Yl2I6T9NQJCkZ+D3UlhLbIwm5Ij1j"
|
|
34
|
+
"EuKtBOEnGc+/sA5zv/ddpMtsx5PGimW/wdLf34+X33gTl319ImdsgRMrhmS2gHBEkyLNCVyEP8At"
|
|
35
|
+
"SVG9HoDg/qh6JzId7RNp5p5pRov5v08TQr+AJXmtTTFceP5YvLl5C/LklvTA4/fh8SeexsRvTcaw"
|
|
36
|
+
"IW0ok+h8dxbBeAReD01jMMBJSGH7tU576YgFub0oUfuCiLYk8Nn+T5DlZPX5w+g+0IGD+zowYtQY"
|
|
37
|
+
"9HCrGoiGTNv6wS2nG1vTdoF9LHvQ2Z0hqYGBSd7xMKatei8Y8oyyUDzm3oMWOhNTpk7Do3/5s+Fc"
|
|
38
|
+
"vzIM+TzY8NpGXHX1XJq0Toq4iJlXz8OY0eMZvoZ7770bAQqZCooHV6/GgoULseRXt2LkyK/irQ0b"
|
|
39
|
+
"sPS3S/HM2mewZ28Hrpk7H1u3vodZs2bg+ut/gpt/fAOeXPMo13utd14c+OQAfnnrEqxatZrPEWp9"
|
|
40
|
+
"cgCSJy6kaoRIo1Idg17zK9IMeWRKeRJNmDRlsvndRT6dQT6XxKZX1mPLv7bi0ssm0bqmcO1VV2Lx"
|
|
41
|
+
"bb/Gu+9vxebXN+HvT6/F9h0dNHv0agNBrH/pRSxccCN27f43vjnxUmOeo+EEzhk8HC+9+CrGnj8O"
|
|
42
|
+
"Lzz/HJ762wOYOn0S1r/yEmhpQeVFjpb15VffwpzZV9Opcbo0cDWPoxdNCrUEijw5LWWzHlLJlCYC"
|
|
43
|
+
"eT/2gnF8KGPL25u5rnXjzY2vYMHNP+V6mce+3R8jQjWZPG0avGGgta0dN9+0AA8+tJprITBkyDm4"
|
|
44
|
+
"5BsTMHbMSJrLPVInmtAkUgyxkAddXUlqWQRdRz41pMycNR3vvf8uNm95m95nFhs3bsGUKVfgvFHD"
|
|
45
|
+
"6cQB8XBsIJJXHbLIs0GxNQRywSJpXPu4TpE2ZlAZDwa1t+G2JYvw8EMPIBoK4umn1mLcBWMw4txm"
|
|
46
|
+
"HNx/ANs++IDaOQUjRk7A+aPHYvHixehJpdHDvfeejg7j+icSYbQPa+eGNosICQiQ6R46ka3Dz0Pn"
|
|
47
|
+
"kW7GOe9Qh4wYhhkzp+PZZ5/FoNawWVt/8MMb6dBpbwr0dHUOTLP5+aD3Jm0jadK8Xvjpgfr8KNHz"
|
|
48
|
+
"9FJq02k6d+/YgXXr1mEwtevbky421jVfKGPOlXOx8bUN2Lt7C7Z99BF27t6He1Yu4wbeefmgbU9P"
|
|
49
|
+
"6giyqS5GcM+YoxfNuukLoUwPNRKJIhELoZv7vGT3EUyfeTlep/n955btKNB8XnDRxcjQjip9cFPr"
|
|
50
|
+
"ACPP/lmMXui5uhdzIhxnxV7p3nu93IZwCyHXXHHhkB8XjRuD22+/A+PHj0eQjmA+XcS0GXPwzrsf"
|
|
51
|
+
"4DWug12deivC/WpFr9GAdBpoHzKUCuznehVAOBZlWtm8fIiEwshxH57loiYHqZBNIxEPIN6UwIRL"
|
|
52
|
+
"LmG5Ntx553I6RfMQjnIZDvvQSk+1mC31P/L0FkEzVG8a9PZDi7r2cYqT8Jw92FHYOCv004IsVYrK"
|
|
53
|
+
"y6FXN+QiMBj0o8x6PFX7abYPDNoLFkp094POG59YNIgrZkynQoZx7fz59DDLNHU+aoQXj6x5Estu"
|
|
54
|
+
"vw2XT52IeEs7pl8xB29t2oSA6mHZdC7PqzHEyHEPV2EDPs4cbttopj3g/OBNEWHuDUu8hkJRTJ0y"
|
|
55
|
+
"Cdu2bcN1181HMqWJ4Lxx8Wtvy86f4ajPDKpOi759hSSczSchDVLlNStlakSi6lq0aJEpe99995n0"
|
|
56
|
+
"Xq/wbGCadoSnix5vueUW84L4D/f/0YnvXfycfNJK/VEbe++nJnJjhr2f7MNXhg9DjmuPn6a1SPdd"
|
|
57
|
+
"fc8cOow2jjXLsXYn0xgcd740dGVoIrnRDlZS8NDB8XJvl01S6wNx7gXLSEQpK18ZmXKenmUGiQhl"
|
|
58
|
+
"wUm25vHn8OL6N7DsjrvolYa1zUOBkyBG77XfaZ4gwiRQaZyIE4lWu+yE0LPSzgriW+rEYZdYVq+d"
|
|
59
|
+
"zFucgD7t6GsBN9MkyAm6V1sMulZNbkGv6dj2sOHnUsjSjgB8kbBZF+EPkTg6I9D7S44jFGHeCvKZ"
|
|
60
|
+
"LGuhmTRq74c3GGFcAeFEnP0o0Inxcv3Lcl3Nc55U0ByJsx3g450dWHHX3bj1Fz/nWkgXlsXLrLdI"
|
|
61
|
+
"FS2SZKdH/Qj2K4LVXvuVQfeWTJsu6F5xIrOoBeY0EHfaBii/hCGTqLo0Kex71BNRJZEhEArhyJEj"
|
|
62
|
+
"XAPZHk0fC3PbQI+yJ02tZBaSm+nqMpMv6Fe9HBMXxhDXOnaTjmyIO48AgrEENUuflTRemu0ITWWp"
|
|
63
|
+
"AL2503Kx8Kaf0TzPwfLfLcd5I4YjRqcmmdJnqRLiJLJQ6ofkSZD2S7U1s9JEkSqSFBRvgxW8iNV6"
|
|
64
|
+
"afOcLCi/CAyGQ+ZZgrLvRtXGiThKnNE+5mtrb6eX6HO+gFNTPCwXI6llraXsQ6S5GS0UMLdv5guB"
|
|
65
|
+
"go9GOsDi3dyzdXZmSBTHmaMn4ykw7hDrL1JT9UkqQA0NYtWqP2EnN/jXzJ2LkF9nepLUvgCiER8+"
|
|
66
|
+
"/ewQHadQ/yNPMFpBSKASsGaxvjjrm5eOHuhbl7RMadYFt6a1ltjPC1rCBF33Hzxg7u23OL0MPxW0"
|
|
67
|
+
"78txvZHZPLh/P4XHiUPT6KPHGKV2lWj68lyUUpk8twMZEzQhmppb6WB4kE7m0MTFrGlQAl6ZaWpj"
|
|
68
|
+
"oZBGcwsXOKXT0yykc8hnC8imNdHUKA0uNbIlEUVXzxHkOW59TtJbogF1AEkal2a61jl9H1OZFEnT"
|
|
69
|
+
"AaQ5s5wDSMYUHgM7v9l3Oi4ybUG5h0Xu++iBZsteZNJJRDkdQiyf4ryTJof15yFZtELPsaDXNNyU"
|
|
70
|
+
"l0ta+UIkmHm8NH9RnRI4TLK4i/eFqVlttOmcBNkKJ4SPGlki8T4UaSI/PXwAg4cMYXkfkuxzcyXU"
|
|
71
|
+
"/8hTugZvP0haUyhSvujRP5FXZBmZO9Ufpjm2R/985i0KJ8EJ3Ttan8o7XiidD5qypHz3YIx7NTo8"
|
|
72
|
+
"FHCRk6wYjDtjyCdJEB0jf5COTYmmUF/gY+Z1m95TymnNZbvQFNcklaUJoCeZgb9EcxynlUlVOH4P"
|
|
73
|
+
"r1lOixzi1LxkLokM62qLD4KPe8t+R15fwyHAwYlEnTk4QgpVZtgZo9f8IVbR6lgM+2zysM3etuht"
|
|
74
|
+
"2kmgOuBRPiUykibSeri2Xmeb4oSjfffCz6ij02qA4OhWoBrxX8IKVwTUEnn8s8lT2xbJon9q8hiQ"
|
|
75
|
+
"TPPXeHVVGXEowkSqIbaaT3VXyVV9+r474Mj7f4JLXgPDJa+B4ZLXwHDJa2C45DUwXPIaGC55DQyX"
|
|
76
|
+
"vAaGS14DwyWvgeGS18BwyWtguOQ1MPqMPH270zc9QedE9Kwv5C7qh7qTZwkT7Fdu+5NcHSRyUT/U"
|
|
77
|
+
"nTwdYbCwX811DkWHhuxfO3BRH9T9GEQtrBbqGETtH8VxUR/0yRkWofZgkDROptNFfdEn5Enjas2n"
|
|
78
|
+
"i75Bn5jN2pNjFsWifljv/MEaF/VBn5Ens1l7BNCS56JeAP4DSJ3/Y5GXBHwAAAAASUVORK5CYII="
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_cf_template() -> bytearray:
|
|
83
|
+
"""Return CF checkbox template image as bytes."""
|
|
84
|
+
return bytearray(base64.b64decode(_CF_TEMPLATE_B64))
|