webctl 0.1.2__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 (57) hide show
  1. webctl-0.1.2/.github/workflows/ci.yml +92 -0
  2. webctl-0.1.2/.github/workflows/publish.yml +29 -0
  3. webctl-0.1.2/.gitignore +41 -0
  4. webctl-0.1.2/.python-version +1 -0
  5. webctl-0.1.2/PKG-INFO +318 -0
  6. webctl-0.1.2/README.md +281 -0
  7. webctl-0.1.2/pyproject.toml +81 -0
  8. webctl-0.1.2/src/webctl/__init__.py +14 -0
  9. webctl-0.1.2/src/webctl/__main__.py +6 -0
  10. webctl-0.1.2/src/webctl/cli/__init__.py +13 -0
  11. webctl-0.1.2/src/webctl/cli/app.py +1095 -0
  12. webctl-0.1.2/src/webctl/cli/commands/__init__.py +0 -0
  13. webctl-0.1.2/src/webctl/cli/output.py +313 -0
  14. webctl-0.1.2/src/webctl/config.py +154 -0
  15. webctl-0.1.2/src/webctl/daemon/__init__.py +14 -0
  16. webctl-0.1.2/src/webctl/daemon/detectors/__init__.py +15 -0
  17. webctl-0.1.2/src/webctl/daemon/detectors/action.py +177 -0
  18. webctl-0.1.2/src/webctl/daemon/detectors/auth.py +260 -0
  19. webctl-0.1.2/src/webctl/daemon/detectors/cookie_banner.py +356 -0
  20. webctl-0.1.2/src/webctl/daemon/detectors/view_change.py +229 -0
  21. webctl-0.1.2/src/webctl/daemon/event_emitter.py +134 -0
  22. webctl-0.1.2/src/webctl/daemon/handlers/__init__.py +11 -0
  23. webctl-0.1.2/src/webctl/daemon/handlers/console.py +90 -0
  24. webctl-0.1.2/src/webctl/daemon/handlers/error_screenshot.py +51 -0
  25. webctl-0.1.2/src/webctl/daemon/handlers/hitl.py +161 -0
  26. webctl-0.1.2/src/webctl/daemon/handlers/interact.py +777 -0
  27. webctl-0.1.2/src/webctl/daemon/handlers/navigation.py +171 -0
  28. webctl-0.1.2/src/webctl/daemon/handlers/observe.py +310 -0
  29. webctl-0.1.2/src/webctl/daemon/handlers/registry.py +31 -0
  30. webctl-0.1.2/src/webctl/daemon/handlers/session.py +280 -0
  31. webctl-0.1.2/src/webctl/daemon/handlers/wait.py +290 -0
  32. webctl-0.1.2/src/webctl/daemon/server.py +200 -0
  33. webctl-0.1.2/src/webctl/daemon/session_manager.py +391 -0
  34. webctl-0.1.2/src/webctl/exceptions.py +119 -0
  35. webctl-0.1.2/src/webctl/protocol/__init__.py +51 -0
  36. webctl-0.1.2/src/webctl/protocol/client.py +76 -0
  37. webctl-0.1.2/src/webctl/protocol/messages.py +133 -0
  38. webctl-0.1.2/src/webctl/protocol/transport.py +415 -0
  39. webctl-0.1.2/src/webctl/query/__init__.py +37 -0
  40. webctl-0.1.2/src/webctl/query/ast.py +97 -0
  41. webctl-0.1.2/src/webctl/query/grammar.py +47 -0
  42. webctl-0.1.2/src/webctl/query/parser.py +136 -0
  43. webctl-0.1.2/src/webctl/query/resolver.py +215 -0
  44. webctl-0.1.2/src/webctl/security/__init__.py +8 -0
  45. webctl-0.1.2/src/webctl/security/domain_policy.py +135 -0
  46. webctl-0.1.2/src/webctl/views/__init__.py +29 -0
  47. webctl-0.1.2/src/webctl/views/a11y.py +352 -0
  48. webctl-0.1.2/src/webctl/views/dom_lite.py +179 -0
  49. webctl-0.1.2/src/webctl/views/export.py +130 -0
  50. webctl-0.1.2/src/webctl/views/filters.py +142 -0
  51. webctl-0.1.2/src/webctl/views/markdown.py +86 -0
  52. webctl-0.1.2/src/webctl/views/redaction.py +61 -0
  53. webctl-0.1.2/tests/__init__.py +0 -0
  54. webctl-0.1.2/tests/integration/__init__.py +0 -0
  55. webctl-0.1.2/tests/test_smoke.py +273 -0
  56. webctl-0.1.2/tests/unit/__init__.py +0 -0
  57. webctl-0.1.2/uv.lock +813 -0
@@ -0,0 +1,92 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+ workflow_dispatch: # Allow manual trigger
9
+
10
+ jobs:
11
+ lint:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v4
18
+ with:
19
+ version: "latest"
20
+
21
+ - name: Set up Python
22
+ run: uv python install 3.12
23
+
24
+ - name: Install dependencies
25
+ run: uv sync --extra dev
26
+
27
+ - name: Run ruff check
28
+ run: uv run ruff check src/
29
+
30
+ - name: Run ruff format check
31
+ run: uv run ruff format --check src/
32
+
33
+ - name: Run mypy
34
+ run: uv run mypy src/
35
+
36
+ test:
37
+ runs-on: ${{ matrix.os }}
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ os: [ubuntu-latest, windows-latest, macos-latest]
42
+ python-version: ["3.11", "3.12"]
43
+
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+
47
+ - name: Install uv
48
+ uses: astral-sh/setup-uv@v4
49
+ with:
50
+ version: "latest"
51
+
52
+ - name: Set up Python ${{ matrix.python-version }}
53
+ run: uv python install ${{ matrix.python-version }}
54
+
55
+ - name: Install dependencies
56
+ run: uv sync --extra dev
57
+
58
+ - name: Install Playwright browsers
59
+ run: uv run playwright install chromium
60
+
61
+ - name: Install Playwright system deps (Linux)
62
+ if: runner.os == 'Linux'
63
+ run: uv run playwright install-deps chromium
64
+
65
+ - name: Run tests
66
+ run: uv run pytest tests/ -v --tb=short
67
+ env:
68
+ CI: "true"
69
+ NO_COLOR: "1"
70
+
71
+ build:
72
+ runs-on: ubuntu-latest
73
+ needs: [lint, test]
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+
77
+ - name: Install uv
78
+ uses: astral-sh/setup-uv@v4
79
+ with:
80
+ version: "latest"
81
+
82
+ - name: Set up Python
83
+ run: uv python install 3.12
84
+
85
+ - name: Build package
86
+ run: uv build
87
+
88
+ - name: Upload artifact
89
+ uses: actions/upload-artifact@v4
90
+ with:
91
+ name: dist
92
+ path: dist/
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ # Semver: v1.0.0, v1.0.0-alpha, v1.0.0-rc.1, v1.0.0+build
7
+ # GitHub Actions only supports glob patterns, not the full semver regex
8
+ - 'v[0-9]*.[0-9]*.[0-9]*'
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ permissions:
15
+ id-token: write # Required for trusted publishing
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v4
22
+
23
+ - name: Build package
24
+ run: |
25
+ uv python install 3.12
26
+ uv build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,41 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ venv/
12
+
13
+ # Testing
14
+ .pytest_cache/
15
+ .coverage
16
+ htmlcov/
17
+ .ruff_cache/
18
+
19
+ # IDE/Editor
20
+ .vscode/
21
+ .idea/
22
+ *.swp
23
+ *.swo
24
+
25
+ # Claude Code
26
+ .claude/
27
+
28
+ # OS
29
+ .DS_Store
30
+ Thumbs.db
31
+
32
+ # Generated docs
33
+ README.html
34
+ README_files/
35
+
36
+ # Temp files
37
+ tmpclaude-*
38
+ *.tmp
39
+
40
+ # mypy
41
+ .mypy_cache/
@@ -0,0 +1 @@
1
+ 3.12
webctl-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: webctl
3
+ Version: 0.1.2
4
+ Summary: Browser automation via CLI — for humans and agents
5
+ Project-URL: Homepage, https://github.com/cosinusalpha/webctl
6
+ Project-URL: Repository, https://github.com/cosinusalpha/webctl
7
+ Project-URL: Issues, https://github.com/cosinusalpha/webctl/issues
8
+ Author-email: cosinusalpha <42695699+cosinusalpha@users.noreply.github.com>
9
+ License: MIT
10
+ Keywords: agent,automation,browser,cli,web
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: aiofiles>=24.0.0
22
+ Requires-Dist: deepdiff>=7.0.0
23
+ Requires-Dist: lark>=1.1.0
24
+ Requires-Dist: markdownify>=0.13.0
25
+ Requires-Dist: playwright>=1.40.0
26
+ Requires-Dist: pydantic>=2.0.0
27
+ Requires-Dist: rich>=13.0.0
28
+ Requires-Dist: typer>=0.12.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
32
+ Requires-Dist: pytest-playwright>=0.5.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
35
+ Requires-Dist: types-aiofiles>=24.0.0; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # webctl
39
+
40
+ **Browser automation for AI agents and humans, built on the command line.**
41
+
42
+ ```bash
43
+ webctl start
44
+ webctl navigate "https://google.com"
45
+ webctl type 'role=combobox name~="Search"' "best restaurants nearby" --submit
46
+ webctl snapshot --interactive-only --limit 20
47
+ webctl stop --daemon
48
+ ```
49
+
50
+ ## Why CLI Instead of MCP?
51
+
52
+ MCP browser tools have a fundamental problem: **the server controls what enters your context**. With Playwright MCP, every response includes the full accessibility tree plus console messages (default: "info" level). After a few page queries, your context is full.
53
+
54
+ CLI flips this around: **you control what enters context**.
55
+
56
+ ```bash
57
+ # Filter before context
58
+ webctl snapshot --interactive-only --limit 30 # Only buttons, links, inputs
59
+ webctl snapshot --within "role=main" # Skip nav, footer, ads
60
+
61
+ # Pipe through Unix tools
62
+ webctl snapshot | grep -i "submit" # Find specific elements
63
+ webctl --format jsonl snapshot | jq '.data.role' # Extract with jq
64
+ webctl snapshot | head -50 # Truncate output
65
+ ```
66
+
67
+ Beyond filtering, CLI gives you:
68
+
69
+ | Capability | CLI | MCP |
70
+ |------------|-----|-----|
71
+ | **Filter output** | Built-in flags + grep/jq/head | Server decides |
72
+ | **Debug** | Run same command as agent | Opaque |
73
+ | **Cache** | `webctl snapshot > cache.txt` | Every call hits server |
74
+ | **Script** | Save to .sh, version control | Ephemeral |
75
+ | **Timeout** | `timeout 30 webctl ...` | Internal only |
76
+ | **Parallelize** | `parallel`, `xargs`, `&` | Server-dependent |
77
+ | **Human takeover** | Same commands | Different interface |
78
+
79
+ ## Quick Start
80
+
81
+ ```bash
82
+ pip install webctl # Requires Python 3.11+
83
+ webctl setup # Downloads Chromium (~150MB)
84
+ ```
85
+
86
+ Verify it works:
87
+
88
+ ```bash
89
+ webctl start
90
+ webctl navigate "https://example.com"
91
+ webctl snapshot --interactive-only
92
+ webctl stop --daemon
93
+ ```
94
+
95
+ <details>
96
+ <summary>Install from source</summary>
97
+
98
+ ```bash
99
+ git clone https://github.com/cosinusalpha/webctl
100
+ cd webctl
101
+ uv sync && uv run webctl setup
102
+ ```
103
+
104
+ </details>
105
+
106
+ <details>
107
+ <summary>Linux system dependencies</summary>
108
+
109
+ ```bash
110
+ playwright install-deps chromium
111
+ # Or manually: sudo apt-get install libnss3 libatk1.0-0 libatk-bridge2.0-0 ...
112
+ ```
113
+
114
+ </details>
115
+
116
+ ## Core Concepts
117
+
118
+ ### Sessions
119
+
120
+ Browser stays open across commands. Cookies persist to disk.
121
+
122
+ ```bash
123
+ webctl start # Visible browser
124
+ webctl start --mode unattended # Headless
125
+ webctl -s work start # Named profile (separate cookies)
126
+ webctl stop --daemon # Shutdown everything
127
+ ```
128
+
129
+ ### Element Queries
130
+
131
+ Semantic targeting based on ARIA roles - stable across CSS refactors:
132
+
133
+ ```bash
134
+ role=button # Any button
135
+ role=button name="Submit" # Exact match
136
+ role=button name~="Submit" # Contains (preferred)
137
+ role=textbox name~="Email" # Input field
138
+ role=link name~="Sign in" # Link
139
+ ```
140
+
141
+ ### Output Control
142
+
143
+ ```bash
144
+ webctl snapshot # Human-readable
145
+ webctl --quiet navigate "..." # Suppress events
146
+ webctl --result-only --format jsonl navigate "..." # Pure JSON, final result only
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Commands
152
+
153
+ ### Navigation
154
+
155
+ ```bash
156
+ webctl navigate "https://..." # Go to URL
157
+ webctl back # History back
158
+ webctl forward # History forward
159
+ webctl reload # Refresh
160
+ ```
161
+
162
+ ### Observation
163
+
164
+ ```bash
165
+ webctl snapshot # Full a11y tree
166
+ webctl snapshot --interactive-only # Buttons, links, inputs only
167
+ webctl snapshot --limit 30 # Cap output
168
+ webctl snapshot --within "role=main" # Scope to container
169
+ webctl snapshot --roles "button,link" # Filter by role
170
+ webctl query "role=button name~=Submit" # Debug query, get suggestions
171
+ webctl screenshot --path shot.png # Screenshot
172
+ ```
173
+
174
+ ### Interaction
175
+
176
+ ```bash
177
+ webctl click 'role=button name~="Submit"'
178
+ webctl type 'role=textbox name~="Email"' "user@example.com"
179
+ webctl type 'role=textbox name~="Search"' "query" --submit # Type + Enter
180
+ webctl select 'role=combobox name~="Country"' --label "Germany"
181
+ webctl check 'role=checkbox name~="Remember"'
182
+ webctl press Enter
183
+ webctl scroll down
184
+ webctl upload 'role=button name~="Upload"' --file ./doc.pdf
185
+ ```
186
+
187
+ ### Wait Conditions
188
+
189
+ ```bash
190
+ webctl wait network-idle
191
+ webctl wait 'exists:role=button name~="Continue"'
192
+ webctl wait 'visible:role=dialog'
193
+ webctl wait 'hidden:role=progressbar'
194
+ webctl wait 'url-contains:"/dashboard"'
195
+ ```
196
+
197
+ ### Session Management
198
+
199
+ ```bash
200
+ webctl status # Current state (includes console error counts)
201
+ webctl save # Persist cookies now
202
+ webctl sessions # List profiles
203
+ webctl pages # List tabs
204
+ webctl focus p2 # Switch tab
205
+ webctl close-page p1 # Close tab
206
+ ```
207
+
208
+ ### Console Logs
209
+
210
+ ```bash
211
+ webctl console # Get last 100 logs
212
+ webctl console --count # Just counts by level (LLM-friendly)
213
+ webctl console --level error # Filter to errors only
214
+ webctl console --follow # Stream new logs continuously
215
+ webctl console -n 50 -l warn # Last 50 warnings
216
+ ```
217
+
218
+ ### Setup & Config
219
+
220
+ ```bash
221
+ webctl setup # Install browser
222
+ webctl doctor # Diagnose installation
223
+ webctl init # Add to agent configs (CLAUDE.md, etc.)
224
+ webctl config show # Show settings
225
+ webctl config set idle_timeout 1800
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Agent Integration
231
+
232
+ Tell your AI agent to use webctl. The easiest way:
233
+
234
+ ```bash
235
+ webctl init # Creates CLAUDE.md, GEMINI.md, etc.
236
+ webctl init --agents claude # Only specific agents
237
+ ```
238
+
239
+ Or manually add to your agent's config:
240
+
241
+ ```
242
+ For web browsing, use webctl CLI. Run `webctl agent-prompt` for instructions.
243
+ ```
244
+
245
+ ---
246
+
247
+ ## For AI Agents
248
+
249
+ *This section is designed to be read by AI agents directly.*
250
+
251
+ ### webctl Quick Reference
252
+
253
+ Control a browser via CLI. Start with `webctl start`, end with `webctl stop --daemon`.
254
+
255
+ **Commands:**
256
+
257
+ ```bash
258
+ webctl start # Open browser
259
+ webctl navigate "URL" # Go to URL
260
+ webctl snapshot --interactive-only # See clickable elements
261
+ webctl click 'role=button name~="Text"' # Click element
262
+ webctl type 'role=textbox name~="Field"' "text" # Type
263
+ webctl type 'role=textbox name~="Field"' "text" --submit # Type + Enter
264
+ webctl select 'role=combobox' --label "Option" # Dropdown
265
+ webctl wait 'exists:role=button name~="..."' # Wait for element
266
+ webctl stop --daemon # Close browser
267
+ ```
268
+
269
+ **Query syntax:**
270
+
271
+ - `role=button` - By ARIA role (button, link, textbox, combobox, checkbox)
272
+ - `name~="partial"` - Partial match (preferred, more robust)
273
+ - `name="exact"` - Exact match
274
+
275
+ **Example - Login:**
276
+
277
+ ```bash
278
+ webctl start
279
+ webctl navigate "https://site.com/login"
280
+ webctl type 'role=textbox name~="Email"' "user@example.com"
281
+ webctl type 'role=textbox name~="Password"' "secret" --submit
282
+ webctl wait 'url-contains:"/dashboard"'
283
+ ```
284
+
285
+ **Tips:**
286
+
287
+ - Use `--interactive-only` to reduce output (only buttons, links, inputs)
288
+ - Use `name~=` for partial matching (handles minor text changes)
289
+ - Use `webctl query "..."` if element not found - shows suggestions
290
+ - Use `--quiet` to suppress event output
291
+ - Sessions persist cookies - login once, stay logged in
292
+ - Check `webctl status` for console error counts before investigating
293
+ - Use `webctl console --count` for log summary, `--level error` for details
294
+
295
+ ---
296
+
297
+ ## Architecture
298
+
299
+ ```
300
+ ┌─────────────┐ TCP/IPC ┌─────────────┐
301
+ │ CLI │ ◄──────────────► │ Daemon │
302
+ │ (webctl) │ JSON-RPC │ (browser) │
303
+ └─────────────┘ └─────────────┘
304
+ │ │
305
+ ▼ ▼
306
+ Agent/User Chromium + Playwright
307
+ ```
308
+
309
+ - **CLI**: Stateless, sends commands to daemon
310
+ - **Daemon**: Manages browser, auto-starts on first command
311
+ - **Profiles**: `~/.local/share/webctl/profiles/`
312
+ - **Config**: `~/.config/webctl/config.json`
313
+
314
+ ---
315
+
316
+ ## License
317
+
318
+ MIT