connectonion 0.5.8__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.
- connectonion/__init__.py +78 -0
- connectonion/address.py +320 -0
- connectonion/agent.py +450 -0
- connectonion/announce.py +84 -0
- connectonion/asgi.py +287 -0
- connectonion/auto_debug_exception.py +181 -0
- connectonion/cli/__init__.py +3 -0
- connectonion/cli/browser_agent/__init__.py +5 -0
- connectonion/cli/browser_agent/browser.py +243 -0
- connectonion/cli/browser_agent/prompt.md +107 -0
- connectonion/cli/commands/__init__.py +1 -0
- connectonion/cli/commands/auth_commands.py +527 -0
- connectonion/cli/commands/browser_commands.py +27 -0
- connectonion/cli/commands/create.py +511 -0
- connectonion/cli/commands/deploy_commands.py +220 -0
- connectonion/cli/commands/doctor_commands.py +173 -0
- connectonion/cli/commands/init.py +469 -0
- connectonion/cli/commands/project_cmd_lib.py +828 -0
- connectonion/cli/commands/reset_commands.py +149 -0
- connectonion/cli/commands/status_commands.py +168 -0
- connectonion/cli/docs/co-vibecoding-principles-docs-contexts-all-in-one.md +2010 -0
- connectonion/cli/docs/connectonion.md +1256 -0
- connectonion/cli/docs.md +123 -0
- connectonion/cli/main.py +148 -0
- connectonion/cli/templates/meta-agent/README.md +287 -0
- connectonion/cli/templates/meta-agent/agent.py +196 -0
- connectonion/cli/templates/meta-agent/prompts/answer_prompt.md +9 -0
- connectonion/cli/templates/meta-agent/prompts/docs_retrieve_prompt.md +15 -0
- connectonion/cli/templates/meta-agent/prompts/metagent.md +71 -0
- connectonion/cli/templates/meta-agent/prompts/think_prompt.md +18 -0
- connectonion/cli/templates/minimal/README.md +56 -0
- connectonion/cli/templates/minimal/agent.py +40 -0
- connectonion/cli/templates/playwright/README.md +118 -0
- connectonion/cli/templates/playwright/agent.py +336 -0
- connectonion/cli/templates/playwright/prompt.md +102 -0
- connectonion/cli/templates/playwright/requirements.txt +3 -0
- connectonion/cli/templates/web-research/agent.py +122 -0
- connectonion/connect.py +128 -0
- connectonion/console.py +539 -0
- connectonion/debug_agent/__init__.py +13 -0
- connectonion/debug_agent/agent.py +45 -0
- connectonion/debug_agent/prompts/debug_assistant.md +72 -0
- connectonion/debug_agent/runtime_inspector.py +406 -0
- connectonion/debug_explainer/__init__.py +10 -0
- connectonion/debug_explainer/explain_agent.py +114 -0
- connectonion/debug_explainer/explain_context.py +263 -0
- connectonion/debug_explainer/explainer_prompt.md +29 -0
- connectonion/debug_explainer/root_cause_analysis_prompt.md +43 -0
- connectonion/debugger_ui.py +1039 -0
- connectonion/decorators.py +208 -0
- connectonion/events.py +248 -0
- connectonion/execution_analyzer/__init__.py +9 -0
- connectonion/execution_analyzer/execution_analysis.py +93 -0
- connectonion/execution_analyzer/execution_analysis_prompt.md +47 -0
- connectonion/host.py +579 -0
- connectonion/interactive_debugger.py +342 -0
- connectonion/llm.py +801 -0
- connectonion/llm_do.py +307 -0
- connectonion/logger.py +300 -0
- connectonion/prompt_files/__init__.py +1 -0
- connectonion/prompt_files/analyze_contact.md +62 -0
- connectonion/prompt_files/eval_expected.md +12 -0
- connectonion/prompt_files/react_evaluate.md +11 -0
- connectonion/prompt_files/react_plan.md +16 -0
- connectonion/prompt_files/reflect.md +22 -0
- connectonion/prompts.py +144 -0
- connectonion/relay.py +200 -0
- connectonion/static/docs.html +688 -0
- connectonion/tool_executor.py +279 -0
- connectonion/tool_factory.py +186 -0
- connectonion/tool_registry.py +105 -0
- connectonion/trust.py +166 -0
- connectonion/trust_agents.py +71 -0
- connectonion/trust_functions.py +88 -0
- connectonion/tui/__init__.py +57 -0
- connectonion/tui/divider.py +39 -0
- connectonion/tui/dropdown.py +251 -0
- connectonion/tui/footer.py +31 -0
- connectonion/tui/fuzzy.py +56 -0
- connectonion/tui/input.py +278 -0
- connectonion/tui/keys.py +35 -0
- connectonion/tui/pick.py +130 -0
- connectonion/tui/providers.py +155 -0
- connectonion/tui/status_bar.py +163 -0
- connectonion/usage.py +161 -0
- connectonion/useful_events_handlers/__init__.py +16 -0
- connectonion/useful_events_handlers/reflect.py +116 -0
- connectonion/useful_plugins/__init__.py +20 -0
- connectonion/useful_plugins/calendar_plugin.py +163 -0
- connectonion/useful_plugins/eval.py +139 -0
- connectonion/useful_plugins/gmail_plugin.py +162 -0
- connectonion/useful_plugins/image_result_formatter.py +127 -0
- connectonion/useful_plugins/re_act.py +78 -0
- connectonion/useful_plugins/shell_approval.py +159 -0
- connectonion/useful_tools/__init__.py +44 -0
- connectonion/useful_tools/diff_writer.py +192 -0
- connectonion/useful_tools/get_emails.py +183 -0
- connectonion/useful_tools/gmail.py +1596 -0
- connectonion/useful_tools/google_calendar.py +613 -0
- connectonion/useful_tools/memory.py +380 -0
- connectonion/useful_tools/microsoft_calendar.py +604 -0
- connectonion/useful_tools/outlook.py +488 -0
- connectonion/useful_tools/send_email.py +205 -0
- connectonion/useful_tools/shell.py +97 -0
- connectonion/useful_tools/slash_command.py +201 -0
- connectonion/useful_tools/terminal.py +285 -0
- connectonion/useful_tools/todo_list.py +241 -0
- connectonion/useful_tools/web_fetch.py +216 -0
- connectonion/xray.py +467 -0
- connectonion-0.5.8.dist-info/METADATA +741 -0
- connectonion-0.5.8.dist-info/RECORD +113 -0
- connectonion-0.5.8.dist-info/WHEEL +4 -0
- connectonion-0.5.8.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""Browser Agent for CLI - Natural language browser automation.
|
|
2
|
+
|
|
3
|
+
This module provides a browser automation agent that understands natural language
|
|
4
|
+
requests for taking screenshots and other browser operations via the ConnectOnion CLI.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from connectonion import Agent, llm_do, xray
|
|
11
|
+
from dotenv import load_dotenv
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
# Default screenshots directory in current working directory
|
|
15
|
+
SCREENSHOTS_DIR = Path.cwd() / ".tmp"
|
|
16
|
+
|
|
17
|
+
# Check Playwright availability
|
|
18
|
+
try:
|
|
19
|
+
from playwright.sync_api import sync_playwright
|
|
20
|
+
PLAYWRIGHT_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
PLAYWRIGHT_AVAILABLE = False
|
|
23
|
+
|
|
24
|
+
# Path to the browser agent system prompt
|
|
25
|
+
PROMPT_PATH = Path(__file__).parent / "prompt.md"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class BrowserAutomation:
|
|
29
|
+
"""Browser automation for screenshots and interactions."""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self._screenshots = []
|
|
33
|
+
self._playwright = None
|
|
34
|
+
self._browser = None
|
|
35
|
+
self._page = None
|
|
36
|
+
self._initialize_browser()
|
|
37
|
+
|
|
38
|
+
def _initialize_browser(self):
|
|
39
|
+
"""Initialize the browser instance."""
|
|
40
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
41
|
+
return
|
|
42
|
+
from playwright.sync_api import sync_playwright
|
|
43
|
+
self._playwright = sync_playwright().start()
|
|
44
|
+
self._browser = self._playwright.chromium.launch(headless=True)
|
|
45
|
+
self._page = self._browser.new_page()
|
|
46
|
+
|
|
47
|
+
def navigate_to(self, url: str) -> str:
|
|
48
|
+
"""Navigate to a URL."""
|
|
49
|
+
if not url.startswith(('http://', 'https://')):
|
|
50
|
+
url = f'https://{url}' if '.' in url else f'http://{url}'
|
|
51
|
+
self._page.goto(url, wait_until='networkidle', timeout=30000)
|
|
52
|
+
# Sleep for 2 seconds to ensure page is fully loaded
|
|
53
|
+
self._page.wait_for_timeout(2000)
|
|
54
|
+
return f"Navigated to {url}"
|
|
55
|
+
|
|
56
|
+
def set_viewport(self, width: int, height: int) -> str:
|
|
57
|
+
"""Set the browser viewport size.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
width: Viewport width in pixels
|
|
61
|
+
height: Viewport height in pixels
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Success message
|
|
65
|
+
"""
|
|
66
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
67
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
68
|
+
self._page.set_viewport_size({"width": width, "height": height})
|
|
69
|
+
return f"Viewport set to {width}x{height}"
|
|
70
|
+
|
|
71
|
+
def take_screenshot(self, url: str, path: str = "",
|
|
72
|
+
width: int = 1920, height: int = 1080,
|
|
73
|
+
full_page: bool = False) -> str:
|
|
74
|
+
"""Take a screenshot of the specified URL.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
url: The URL to screenshot (e.g., "localhost:3000", "example.com")
|
|
78
|
+
path: Optional path to save the screenshot (auto-generates if empty)
|
|
79
|
+
width: Viewport width in pixels (default 1920)
|
|
80
|
+
height: Viewport height in pixels (default 1080)
|
|
81
|
+
full_page: If True, captures entire page height
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Success or error message
|
|
85
|
+
"""
|
|
86
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
87
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
88
|
+
|
|
89
|
+
# Navigate to URL
|
|
90
|
+
self.navigate_to(url)
|
|
91
|
+
|
|
92
|
+
# Set viewport size
|
|
93
|
+
self._page.set_viewport_size({"width": width, "height": height})
|
|
94
|
+
|
|
95
|
+
# Generate filename if needed
|
|
96
|
+
if not path:
|
|
97
|
+
# Ensure screenshots directory exists
|
|
98
|
+
SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
100
|
+
path = str(SCREENSHOTS_DIR / f'screenshot_{timestamp}.png')
|
|
101
|
+
elif not path.startswith('/'): # Relative path
|
|
102
|
+
# If relative path given, save to screenshots dir
|
|
103
|
+
SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
if not path.endswith(('.png', '.jpg', '.jpeg')):
|
|
105
|
+
path += '.png'
|
|
106
|
+
path = str(SCREENSHOTS_DIR / path)
|
|
107
|
+
elif not path.endswith(('.png', '.jpg', '.jpeg')):
|
|
108
|
+
# Absolute path without extension
|
|
109
|
+
path += '.png'
|
|
110
|
+
|
|
111
|
+
# Ensure directory exists
|
|
112
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
|
|
114
|
+
# Take screenshot
|
|
115
|
+
self._page.screenshot(path=path, full_page=full_page)
|
|
116
|
+
|
|
117
|
+
self._screenshots.append(path)
|
|
118
|
+
return f'Screenshot saved: {path}'
|
|
119
|
+
|
|
120
|
+
def screenshot_with_iphone_viewport(self, url: str, path: str = "") -> str:
|
|
121
|
+
"""Take a screenshot with iPhone viewport (390x844)."""
|
|
122
|
+
return self.take_screenshot(url, path, width=390, height=844)
|
|
123
|
+
|
|
124
|
+
def screenshot_with_ipad_viewport(self, url: str, path: str = "") -> str:
|
|
125
|
+
"""Take a screenshot with iPad viewport (768x1024)."""
|
|
126
|
+
return self.take_screenshot(url, path, width=768, height=1024)
|
|
127
|
+
|
|
128
|
+
def screenshot_with_desktop_viewport(self, url: str, path: str = "") -> str:
|
|
129
|
+
"""Take a screenshot with desktop viewport (1920x1080)."""
|
|
130
|
+
return self.take_screenshot(url, path, width=1920, height=1080)
|
|
131
|
+
|
|
132
|
+
def get_current_page_html(self) -> str:
|
|
133
|
+
"""Get the HTML content of the current page.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
The HTML content of the current page
|
|
137
|
+
"""
|
|
138
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
139
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
140
|
+
return self._page.content()
|
|
141
|
+
|
|
142
|
+
def get_current_url(self) -> str:
|
|
143
|
+
"""Get the current page URL.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
The current URL
|
|
147
|
+
"""
|
|
148
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
149
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
150
|
+
return self._page.url
|
|
151
|
+
|
|
152
|
+
def wait(self, seconds: float) -> str:
|
|
153
|
+
"""Wait for a specified number of seconds.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
seconds: Number of seconds to wait
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Success message
|
|
160
|
+
"""
|
|
161
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
162
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
163
|
+
self._page.wait_for_timeout(seconds * 1000) # Convert to milliseconds
|
|
164
|
+
return f"Waited for {seconds} seconds"
|
|
165
|
+
|
|
166
|
+
@xray
|
|
167
|
+
def get_debug_trace(self) -> str:
|
|
168
|
+
"""Get execution trace for debugging.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Execution trace showing what happened
|
|
172
|
+
"""
|
|
173
|
+
if hasattr(xray, 'trace'):
|
|
174
|
+
return xray.trace()
|
|
175
|
+
return "No trace available"
|
|
176
|
+
|
|
177
|
+
def click_element_by_description(self, description: str) -> str:
|
|
178
|
+
"""Click an element on the current page based on natural language description.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
description: Natural language description of what to click
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Result message
|
|
185
|
+
"""
|
|
186
|
+
if not PLAYWRIGHT_AVAILABLE:
|
|
187
|
+
return 'Browser tools not installed. Run: pip install playwright && playwright install chromium'
|
|
188
|
+
|
|
189
|
+
html_content = self._page.content()
|
|
190
|
+
|
|
191
|
+
# Use llm_do to determine the selector
|
|
192
|
+
class ElementSelector(BaseModel):
|
|
193
|
+
selector: str
|
|
194
|
+
method: str # "text" or "css"
|
|
195
|
+
|
|
196
|
+
result = llm_do(
|
|
197
|
+
f"Find selector for: {description}\n\nHTML:\n{html_content[:5000]}",
|
|
198
|
+
output=ElementSelector,
|
|
199
|
+
system_prompt="Return the best selector to click the element. Use method='text' for button text, method='css' for CSS selectors."
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if result.method == "text":
|
|
203
|
+
self._page.get_by_text(result.selector).click()
|
|
204
|
+
else:
|
|
205
|
+
self._page.locator(result.selector).click()
|
|
206
|
+
|
|
207
|
+
self._page.wait_for_timeout(1000)
|
|
208
|
+
return f"Clicked: {result.selector}"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def execute_browser_command(command: str) -> str:
|
|
215
|
+
"""Execute a browser command using natural language.
|
|
216
|
+
|
|
217
|
+
Returns the agent's natural language response directly.
|
|
218
|
+
"""
|
|
219
|
+
# Framework auto-loads local .env, but CLI commands need global fallback
|
|
220
|
+
# Check for API key in environment first
|
|
221
|
+
api_key = os.getenv('OPENONION_API_KEY')
|
|
222
|
+
|
|
223
|
+
# If not found, try loading from global config
|
|
224
|
+
if not api_key:
|
|
225
|
+
global_env = Path.home() / ".co" / "keys.env"
|
|
226
|
+
if global_env.exists():
|
|
227
|
+
load_dotenv(global_env)
|
|
228
|
+
api_key = os.getenv('OPENONION_API_KEY')
|
|
229
|
+
|
|
230
|
+
if not api_key:
|
|
231
|
+
return '❌ Browser agent requires authentication. Run: co auth'
|
|
232
|
+
|
|
233
|
+
browser = BrowserAutomation()
|
|
234
|
+
agent = Agent(
|
|
235
|
+
name="browser_cli",
|
|
236
|
+
model="co/gemini-2.5-pro",
|
|
237
|
+
api_key=api_key,
|
|
238
|
+
system_prompt=PROMPT_PATH,
|
|
239
|
+
tools=[browser],
|
|
240
|
+
max_iterations=10
|
|
241
|
+
)
|
|
242
|
+
return agent.input(command)
|
|
243
|
+
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Browser CLI Assistant
|
|
2
|
+
|
|
3
|
+
You are a browser automation assistant that understands natural language requests for browser automation including navigation, interaction, screenshots, and debugging.
|
|
4
|
+
|
|
5
|
+
## Your Available Functions
|
|
6
|
+
|
|
7
|
+
### Navigation & State
|
|
8
|
+
- `navigate_to(url)` - Navigate to any website
|
|
9
|
+
- `get_current_url()` - Get the current page URL
|
|
10
|
+
- `get_current_page_html()` - Get HTML content of current page
|
|
11
|
+
- `wait(seconds)` - Wait for specified seconds (useful after navigation or clicks)
|
|
12
|
+
|
|
13
|
+
### Viewport & Display
|
|
14
|
+
- `set_viewport(width, height)` - Set custom viewport dimensions
|
|
15
|
+
- `screenshot_with_iphone_viewport(url, path)` - Take screenshot with iPhone size (390x844)
|
|
16
|
+
- `screenshot_with_ipad_viewport(url, path)` - Take screenshot with iPad size (768x1024)
|
|
17
|
+
- `screenshot_with_desktop_viewport(url, path)` - Take screenshot with desktop size (1920x1080)
|
|
18
|
+
- `take_screenshot(url, path, width, height, full_page)` - Take screenshot with all options
|
|
19
|
+
|
|
20
|
+
### Interaction
|
|
21
|
+
- `click_element_by_description(description)` - Click elements using natural language (e.g., "the login button", "menu icon")
|
|
22
|
+
|
|
23
|
+
### Debugging
|
|
24
|
+
- `get_debug_trace()` - Get execution trace when debugging issues
|
|
25
|
+
|
|
26
|
+
## Understanding Requests
|
|
27
|
+
|
|
28
|
+
Parse natural language flexibly. Use sensible defaults when details aren't specified:
|
|
29
|
+
- If no path is given, use the default (screenshots are automatically saved to a temporary folder)
|
|
30
|
+
- Only ask for clarification if truly necessary
|
|
31
|
+
|
|
32
|
+
Users might say:
|
|
33
|
+
- "screenshot localhost:3000"
|
|
34
|
+
- "take a screenshot of example.com"
|
|
35
|
+
- "capture google.com and save it to /tmp/test.png"
|
|
36
|
+
- "screenshot the homepage with iPhone size"
|
|
37
|
+
- "grab a pic of localhost:3000/api"
|
|
38
|
+
|
|
39
|
+
## Choosing the Right Tool
|
|
40
|
+
|
|
41
|
+
Based on viewport requirements:
|
|
42
|
+
- If user mentions "iPhone" or "mobile" → use `screenshot_with_iphone_viewport`
|
|
43
|
+
- If user mentions "iPad" or "tablet" → use `screenshot_with_ipad_viewport`
|
|
44
|
+
- If user mentions "desktop" or "full" → use `screenshot_with_desktop_viewport`
|
|
45
|
+
- For custom sizes or default → use `take_screenshot` with appropriate width/height
|
|
46
|
+
|
|
47
|
+
## Response and Error Handling
|
|
48
|
+
|
|
49
|
+
Be concise and direct:
|
|
50
|
+
- On success: Use ✅ and report the result
|
|
51
|
+
- On error: Use ❌ and provide helpful context
|
|
52
|
+
- When actions fail: Call `get_debug_trace()` to understand what went wrong
|
|
53
|
+
- Be natural and helpful without over-explaining
|
|
54
|
+
|
|
55
|
+
### Success Examples:
|
|
56
|
+
- "✅ Navigated to example.com"
|
|
57
|
+
- "✅ Clicked the login button"
|
|
58
|
+
- "✅ Screenshot saved: .tmp/screenshot_20240101_120000.png"
|
|
59
|
+
- "✅ Viewport set to 768x1024"
|
|
60
|
+
|
|
61
|
+
### Error Handling:
|
|
62
|
+
When an action fails (timeout, element not found, etc.):
|
|
63
|
+
1. Report the error clearly
|
|
64
|
+
2. Use `get_debug_trace()` if the issue is unclear
|
|
65
|
+
3. Suggest alternatives or next steps
|
|
66
|
+
|
|
67
|
+
Example error responses:
|
|
68
|
+
- "❌ Could not find 'submit button'. The element may not be visible or loaded yet."
|
|
69
|
+
- "❌ Navigation timeout. The page took too long to load."
|
|
70
|
+
- "❌ Click failed. Let me check the debug trace... [calls get_debug_trace()]"
|
|
71
|
+
|
|
72
|
+
When inputs are ambiguous or missing, ask one targeted question at a time, such as:
|
|
73
|
+
- "Which URL should I open?"
|
|
74
|
+
- "Do you want full-page or just the current viewport?"
|
|
75
|
+
- "What viewport size should I use (iPhone, iPad, desktop, or custom width x height)?"
|
|
76
|
+
|
|
77
|
+
## Examples
|
|
78
|
+
|
|
79
|
+
### Basic Navigation
|
|
80
|
+
User: "go to example.com and get the HTML"
|
|
81
|
+
→ navigate_to("example.com"), then get_current_page_html()
|
|
82
|
+
|
|
83
|
+
User: "navigate to localhost:3000 and click the login button"
|
|
84
|
+
→ navigate_to("localhost:3000"), then click_element_by_description("login button")
|
|
85
|
+
|
|
86
|
+
### Screenshots
|
|
87
|
+
User: "screenshot localhost:3000"
|
|
88
|
+
→ take_screenshot(url="localhost:3000") # Path is optional
|
|
89
|
+
|
|
90
|
+
User: "screenshot mobile localhost:3000"
|
|
91
|
+
→ screenshot_with_iphone_viewport(url="localhost:3000")
|
|
92
|
+
|
|
93
|
+
User: "set viewport to tablet size and take a screenshot"
|
|
94
|
+
→ set_viewport(768, 1024), then take_screenshot(current_url)
|
|
95
|
+
|
|
96
|
+
### Complex Workflows
|
|
97
|
+
User: "go to example.com, click more info link, check if URL changed"
|
|
98
|
+
→ navigate_to("example.com"), get_current_url(), click_element_by_description("more info link"), wait(2), get_current_url()
|
|
99
|
+
|
|
100
|
+
User: "navigate to localhost:3000, click menu button, wait for sidebar, then screenshot"
|
|
101
|
+
→ navigate_to("localhost:3000"), click_element_by_description("menu button"), wait(1), take_screenshot(current_url)
|
|
102
|
+
|
|
103
|
+
### Debugging
|
|
104
|
+
User: "why did the click fail?"
|
|
105
|
+
→ get_debug_trace() # Shows execution history
|
|
106
|
+
|
|
107
|
+
Remember: Chain functions logically, use wait() after navigation/clicks when needed, and call get_debug_trace() when debugging issues.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command modules for ConnectOnion CLI."""
|