agent-cdp 0.1.0__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.
- agent_cdp-0.1.0/.claude/settings.local.json +34 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a0b334a7/.claude/settings.local.json +22 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a0b334a7/.git +1 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a0b334a7/.gitignore +39 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a0b334a7/CLAUDE.md +182 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a0b334a7/pyproject.toml +6 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a76c879b/.claude/settings.local.json +22 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a76c879b/.git +1 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a76c879b/.gitignore +39 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a76c879b/CLAUDE.md +182 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-a76c879b/pyproject.toml +6 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-aaf55f3e/.claude/settings.local.json +22 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-aaf55f3e/.git +1 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-aaf55f3e/.gitignore +39 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-aaf55f3e/CLAUDE.md +182 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-aaf55f3e/pyproject.toml +6 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-afe0f0f9/.claude/settings.local.json +22 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-afe0f0f9/.git +1 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-afe0f0f9/.gitignore +39 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-afe0f0f9/CLAUDE.md +182 -0
- agent_cdp-0.1.0/.claude/worktrees/agent-afe0f0f9/pyproject.toml +6 -0
- agent_cdp-0.1.0/.gitignore +39 -0
- agent_cdp-0.1.0/CLAUDE.md +112 -0
- agent_cdp-0.1.0/LICENSE +21 -0
- agent_cdp-0.1.0/PKG-INFO +332 -0
- agent_cdp-0.1.0/README.md +303 -0
- agent_cdp-0.1.0/analysis/bubus_design_gaps_in_agent_browser_scenario.md +353 -0
- agent_cdp-0.1.0/analysis/development_plan_detailed.md +1491 -0
- agent_cdp-0.1.0/analysis/draft_agent_plan.md +941 -0
- agent_cdp-0.1.0/analysis/proposal_scoped_eventbus.md +1096 -0
- agent_cdp-0.1.0/demo/__init__.py +0 -0
- agent_cdp-0.1.0/demo/bench.py +517 -0
- agent_cdp-0.1.0/demo/cdp_client.py +92 -0
- agent_cdp-0.1.0/demo/chrome.py +62 -0
- agent_cdp-0.1.0/demo/events.py +117 -0
- agent_cdp-0.1.0/demo/main.py +370 -0
- agent_cdp-0.1.0/demo/multi_tab.py +601 -0
- agent_cdp-0.1.0/demo/screenshot.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/bench_bilibili.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/bench_google.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/bench_recaptcha_demo.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/bench_xiaohongshu.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/multi_bilibili.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/multi_google.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/multi_recaptcha.png +0 -0
- agent_cdp-0.1.0/demo/screenshots/multi_xiaohongshu.png +0 -0
- agent_cdp-0.1.0/demo/timing.py +130 -0
- agent_cdp-0.1.0/demo/watchdogs.py +460 -0
- agent_cdp-0.1.0/demo_conscribe_pydantic.py +137 -0
- agent_cdp-0.1.0/pyproject.toml +70 -0
- agent_cdp-0.1.0/qt_ref/qt/01_signals_and_slots.md +212 -0
- agent_cdp-0.1.0/qt_ref/qt/02_connection_type_enum.md +21 -0
- agent_cdp-0.1.0/qt_ref/qt/03_qobject_connect.md +153 -0
- agent_cdp-0.1.0/qt_ref/qt/04_event_system.md +126 -0
- agent_cdp-0.1.0/qt_ref/qt/05_qevent.md +69 -0
- agent_cdp-0.1.0/qt_ref/qt/06_send_post_event.md +137 -0
- agent_cdp-0.1.0/qt_ref/qt/07_threads_and_qobjects.md +63 -0
- agent_cdp-0.1.0/qt_ref/qt/08_qeventloop.md +58 -0
- agent_cdp-0.1.0/qt_ref/qt/09_qthread.md +94 -0
- agent_cdp-0.1.0/qt_ref/qt/10_event_filter.md +75 -0
- agent_cdp-0.1.0/qt_ref/qt/11_property_system.md +169 -0
- agent_cdp-0.1.0/qt_ref/qt/12_state_machine.md +108 -0
- agent_cdp-0.1.0/qt_ref/qt/13_meta_object_system.md +37 -0
- agent_cdp-0.1.0/qt_ref/qt/14_moc.md +116 -0
- agent_cdp-0.1.0/qt_ref/qt/15_woboq_signal_internals.md +102 -0
- agent_cdp-0.1.0/qt_ref/qt/16_gobject_signals.md +71 -0
- agent_cdp-0.1.0/qt_ref/qt/README.md +81 -0
- agent_cdp-0.1.0/src/agent_cdp/__init__.py +1 -0
- agent_cdp-0.1.0/src/agent_cdp/_context.py +18 -0
- agent_cdp-0.1.0/src/agent_cdp/_registry.py +30 -0
- agent_cdp-0.1.0/src/agent_cdp/advanced/__init__.py +7 -0
- agent_cdp-0.1.0/src/agent_cdp/advanced/cycle_detect.py +3 -0
- agent_cdp-0.1.0/src/agent_cdp/advanced/event_log.py +60 -0
- agent_cdp-0.1.0/src/agent_cdp/advanced/expect.py +69 -0
- agent_cdp-0.1.0/src/agent_cdp/advanced/timeout.py +28 -0
- agent_cdp-0.1.0/src/agent_cdp/connection/__init__.py +6 -0
- agent_cdp-0.1.0/src/agent_cdp/connection/connection.py +115 -0
- agent_cdp-0.1.0/src/agent_cdp/connection/types.py +11 -0
- agent_cdp-0.1.0/src/agent_cdp/events/__init__.py +27 -0
- agent_cdp-0.1.0/src/agent_cdp/events/aggregation.py +179 -0
- agent_cdp-0.1.0/src/agent_cdp/events/base.py +158 -0
- agent_cdp-0.1.0/src/agent_cdp/events/result.py +80 -0
- agent_cdp-0.1.0/src/agent_cdp/scope/__init__.py +6 -0
- agent_cdp-0.1.0/src/agent_cdp/scope/_helpers.py +45 -0
- agent_cdp-0.1.0/src/agent_cdp/scope/event_loop.py +185 -0
- agent_cdp-0.1.0/src/agent_cdp/scope/group.py +169 -0
- agent_cdp-0.1.0/src/agent_cdp/scope/scope.py +367 -0
- agent_cdp-0.1.0/tests/__init__.py +0 -0
- agent_cdp-0.1.0/tests/conftest.py +1 -0
- agent_cdp-0.1.0/tests/test_step_1_1_event_result.py +194 -0
- agent_cdp-0.1.0/tests/test_step_1_2_base_event.py +241 -0
- agent_cdp-0.1.0/tests/test_step_1_3_aggregation.py +271 -0
- agent_cdp-0.1.0/tests/test_step_2_1_connection.py +237 -0
- agent_cdp-0.1.0/tests/test_step_2_2_scope_emit.py +570 -0
- agent_cdp-0.1.0/tests/test_step_2_3_event_loop.py +327 -0
- agent_cdp-0.1.0/tests/test_step_3_1_scope_group.py +263 -0
- agent_cdp-0.1.0/tests/test_step_3_2_lifecycle.py +348 -0
- agent_cdp-0.1.0/tests/test_step_4_1_expect_timeout.py +265 -0
- agent_cdp-0.1.0/tests/test_step_4_2_event_log_cycle.py +185 -0
- agent_cdp-0.1.0/uv.lock +425 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebFetch(domain:doc.qt.io)",
|
|
5
|
+
"WebFetch(domain:woboq.com)",
|
|
6
|
+
"WebFetch(domain:docs.gtk.org)",
|
|
7
|
+
"Bash(grep:*)",
|
|
8
|
+
"Bash(wc:*)",
|
|
9
|
+
"Bash(pip show:*)",
|
|
10
|
+
"Bash(python:*)",
|
|
11
|
+
"Bash(ls:*)",
|
|
12
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog -type f -name *.lock -o -name *.toml -o -name *.md)",
|
|
13
|
+
"Bash(python3:*)",
|
|
14
|
+
"Bash(uv sync:*)",
|
|
15
|
+
"Bash(uv run:*)",
|
|
16
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/tests -type f -name *.py)",
|
|
17
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src -type f -name *.py)",
|
|
18
|
+
"Bash(find /root/.claude/projects -name *.md -type f)",
|
|
19
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src/agent_cdp -name \"*.py\" -type f -exec wc -l {} +)",
|
|
20
|
+
"Bash(git -C .claude/worktrees/agent-aaf55f3e status --short)",
|
|
21
|
+
"Bash(git -C .claude/worktrees/agent-a76c879b status --short)",
|
|
22
|
+
"Bash(grep -E '\\\\.\\(py\\)$')",
|
|
23
|
+
"Bash(sort -k2)",
|
|
24
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/bu_ref -name *watchdog*.py -type f)",
|
|
25
|
+
"Bash(echo \"DISPLAY=$DISPLAY\")",
|
|
26
|
+
"Bash(echo \"WAYLAND=$WAYLAND_DISPLAY\")",
|
|
27
|
+
"Bash(pkill -f 'google-chrome.*remote-debugging-port')",
|
|
28
|
+
"Bash(pkill -f 'python -m demo.main')",
|
|
29
|
+
"Bash(pkill -f 'chrome')",
|
|
30
|
+
"Bash(pkill -9 -f 'chrome')",
|
|
31
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/bu_ref -path *cdp*browseruse*events* -type f)"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebFetch(domain:doc.qt.io)",
|
|
5
|
+
"WebFetch(domain:woboq.com)",
|
|
6
|
+
"WebFetch(domain:docs.gtk.org)",
|
|
7
|
+
"Bash(grep:*)",
|
|
8
|
+
"Bash(wc:*)",
|
|
9
|
+
"Bash(pip show:*)",
|
|
10
|
+
"Bash(python:*)",
|
|
11
|
+
"Bash(ls:*)",
|
|
12
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog -type f -name *.lock -o -name *.toml -o -name *.md)",
|
|
13
|
+
"Bash(python3:*)",
|
|
14
|
+
"Bash(uv sync:*)",
|
|
15
|
+
"Bash(uv run:*)",
|
|
16
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/tests -type f -name *.py)",
|
|
17
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src -type f -name *.py)",
|
|
18
|
+
"Bash(find /root/.claude/projects -name *.md -type f)",
|
|
19
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src/agent_cdp -name \"*.py\" -type f -exec wc -l {} +)"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitdir: /root/QLY/code/event_driven_browser_watchdog/.git/worktrees/agent-a0b334a7
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
sdist/
|
|
11
|
+
wheels/
|
|
12
|
+
*.whl
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
|
|
26
|
+
# Testing / Coverage
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Project-specific
|
|
38
|
+
bu_ref/
|
|
39
|
+
references/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This repo is an exploration workspace for browser event-driven design (browser-use edition). It contains three independent but interconnected libraries that together form a layered browser automation stack:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Agent (browser-use) ←→ EventBus (bubus) ←→ CDPClient (cdp-use) ←→ Chrome WebSocket
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The goal is to study how browser-use implements event-driven coordination across ~15 watchdog services, identify architectural strengths and gaps, and experiment with improvements.
|
|
14
|
+
|
|
15
|
+
## Repository Layout
|
|
16
|
+
|
|
17
|
+
| Directory | Package | Description |
|
|
18
|
+
|-----------|---------|-------------|
|
|
19
|
+
| `bubus/` | `bubus==1.5.6` | Pydantic-powered async event bus (pub/sub framework) |
|
|
20
|
+
| `cdp-use/` | `cdp-use==1.4.5` | Auto-generated type-safe Python bindings for Chrome DevTools Protocol |
|
|
21
|
+
| `browser-use/` | `browser-use==0.12.2` | AI browser automation agent that wires the above two together |
|
|
22
|
+
|
|
23
|
+
Each is a standalone `uv`-managed Python project with its own `.venv`, `pyproject.toml`, and test suite. For local development where browser-use depends on local bubus/cdp-use, uncomment `[tool.uv.sources]` in `browser-use/pyproject.toml`.
|
|
24
|
+
|
|
25
|
+
## Development Commands
|
|
26
|
+
|
|
27
|
+
All three use `uv` (Python >=3.11). Run commands from each package's directory.
|
|
28
|
+
|
|
29
|
+
### bubus
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd bubus
|
|
33
|
+
uv sync
|
|
34
|
+
uv run pytest -vxs tests/ # all tests
|
|
35
|
+
uv run pytest -vxs tests/test_eventbus.py # single test file
|
|
36
|
+
uv run ruff check --fix && uv run ruff format # lint + format
|
|
37
|
+
uv run pyright # type check (strict mode)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### cdp-use
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cd cdp-use
|
|
44
|
+
uv sync
|
|
45
|
+
uv run python -m cdp_use.generator # regenerate CDP types from protocol JSON
|
|
46
|
+
uv run ruff check cdp_use/ --statistics # lint
|
|
47
|
+
uv run ruff format cdp_use/ # format
|
|
48
|
+
# Or use: task generate / task lint / task format (Taskfile.yml)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### browser-use
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd browser-use
|
|
55
|
+
uv sync
|
|
56
|
+
uv run pytest -vxs tests/ci # CI test suite (default set)
|
|
57
|
+
uv run pytest -vxs tests/ci/test_foo.py # single test
|
|
58
|
+
uv run ruff check --fix && uv run ruff format # lint + format
|
|
59
|
+
uv run pyright # type check (basic mode)
|
|
60
|
+
uv run pre-commit run --all-files # all pre-commit hooks
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
### Layer 1: bubus — Event Bus
|
|
66
|
+
|
|
67
|
+
Core primitive. Provides `EventBus` and `BaseEvent[T_EventResultType]` (generic over return type).
|
|
68
|
+
|
|
69
|
+
Key capabilities: async dispatch with FIFO queue, `expect()` to await future events, event result aggregation (flat dict / list / by handler ID), handler timeouts, retry decorator with semaphore-based concurrency, event forwarding between bus instances (with loop prevention), Write-Ahead Logging for persistence, child/nested events with parent tracking.
|
|
70
|
+
|
|
71
|
+
### Layer 2: cdp-use — CDP Client
|
|
72
|
+
|
|
73
|
+
Thin typed wrapper over Chrome DevTools Protocol WebSocket. Two main pieces:
|
|
74
|
+
|
|
75
|
+
1. **Generator** (`cdp_use/generator/`) — downloads Chrome protocol JSON specs and generates Python TypedDict classes for all 50+ CDP domains (Page, Runtime, DOM, Network, Target, etc.)
|
|
76
|
+
2. **Client** (`cdp_use/client.py`) — WebSocket client exposing `cdp.send.Domain.method(params={...})` and `cdp.register.Domain.eventName(callback)` with full type safety
|
|
77
|
+
|
|
78
|
+
No event registration via `cdp.on(...)` — only `cdp.register.Domain.event(callback)`.
|
|
79
|
+
|
|
80
|
+
### Layer 3: browser-use — Agent + Watchdogs
|
|
81
|
+
|
|
82
|
+
The orchestration layer. Key architectural patterns:
|
|
83
|
+
|
|
84
|
+
**Service/Views pattern**: each component has `service.py` (logic) and `views.py` (Pydantic models).
|
|
85
|
+
|
|
86
|
+
**BrowserSession** (`browser_use/browser/session.py`) is the hub — manages CDP connections, tab lifecycle, and coordinates watchdogs through a central `EventBus`.
|
|
87
|
+
|
|
88
|
+
**Watchdog pattern** (`browser_use/browser/watchdog_base.py`): Each watchdog is a `BaseWatchdog` subclass (Pydantic model) that declares `LISTENS_TO` and `EMITS` class vars. Handlers auto-register by naming convention: `on_{EventClassName}(self, event)`.
|
|
89
|
+
|
|
90
|
+
15 watchdogs in `browser_use/browser/watchdogs/`:
|
|
91
|
+
- `dom_watchdog` — DOM snapshots, element highlighting, accessibility tree
|
|
92
|
+
- `screenshot_watchdog` — screenshot capture
|
|
93
|
+
- `downloads_watchdog` — file downloads, PDF auto-download
|
|
94
|
+
- `popups_watchdog` — JS dialogs
|
|
95
|
+
- `security_watchdog` — domain restrictions
|
|
96
|
+
- `aboutblank_watchdog` — empty page handling
|
|
97
|
+
- `local_browser_watchdog` — local Chrome process lifecycle
|
|
98
|
+
- `permissions_watchdog` — browser permissions
|
|
99
|
+
- `crash_watchdog` — target crash monitoring
|
|
100
|
+
- `storage_state_watchdog` — cookie/localStorage persistence
|
|
101
|
+
- `captcha_watchdog` — CAPTCHA solver integration
|
|
102
|
+
- `har_recording_watchdog` — network recording (HAR)
|
|
103
|
+
- `recording_watchdog` — browser automation recording
|
|
104
|
+
- `default_action_watchdog` — default action handlers
|
|
105
|
+
|
|
106
|
+
**Events** (`browser_use/browser/events.py`): All events inherit `BaseEvent[T]`. Two categories:
|
|
107
|
+
- Action events (Agent → Browser): `NavigateToUrlEvent`, `ClickElementEvent`, `TypeTextEvent`, `ScreenshotEvent`, `BrowserStartEvent`, etc.
|
|
108
|
+
- Notification events (Browser → Agent/Watchdogs): `BrowserConnectedEvent`, `TabCreatedEvent`, `NavigationCompleteEvent`, `DownloadStartedEvent`, `DialogOpenedEvent`, etc.
|
|
109
|
+
|
|
110
|
+
Event timeouts are configurable via environment variables (`TIMEOUT_NavigateToUrlEvent`, etc.).
|
|
111
|
+
|
|
112
|
+
## Code Style Differences
|
|
113
|
+
|
|
114
|
+
| | bubus | cdp-use | browser-use |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| Indent | spaces | (generated) | **tabs** |
|
|
117
|
+
| Quotes | single | — | single |
|
|
118
|
+
| pyright | strict | — | basic |
|
|
119
|
+
| Line length | 130 | — | 130 |
|
|
120
|
+
|
|
121
|
+
browser-use uses **tabs** for indentation. bubus uses **spaces**. Both use single quotes and ruff for linting/formatting.
|
|
122
|
+
|
|
123
|
+
## Testing Conventions (browser-use)
|
|
124
|
+
|
|
125
|
+
- Tests that pass go into `tests/ci/` — this is the CI-discovered default set
|
|
126
|
+
- **No mocking** except for LLM responses (use `conftest.py` fixtures for LLM mocking)
|
|
127
|
+
- Use `pytest-httpserver` for all test HTML/responses — never use real remote URLs
|
|
128
|
+
- Modern pytest-asyncio: no `@pytest.mark.asyncio` decorator needed, just write `async def test_*()`
|
|
129
|
+
- `asyncio_mode = "auto"` with session-scoped event loop (browser-use) or function-scoped (bubus)
|
|
130
|
+
|
|
131
|
+
## Key Design Decisions to Be Aware Of
|
|
132
|
+
|
|
133
|
+
1. **Shared state belongs on BrowserSession, not on individual watchdogs.** Watchdogs expose state/helpers via events if other watchdogs need access.
|
|
134
|
+
2. **CDP event forwarding**: BrowserSession forwards raw CDP events to watchdogs through the EventBus, not direct CDP callbacks.
|
|
135
|
+
3. **BaseEvent is generic over result type** (`BaseEvent[T_EventResultType]`) — dispatchers can aggregate results from multiple handlers via `event.event_result()`, `event.event_results_list()`, etc.
|
|
136
|
+
4. **Lazy imports** in `browser_use/__init__.py` for startup performance.
|
|
137
|
+
5. **browser-use has its own CLAUDE.md** (`browser-use/CLAUDE.md`) with detailed per-package conventions — read it when working inside browser-use specifically.
|
|
138
|
+
|
|
139
|
+
## Qt Reference Materials
|
|
140
|
+
|
|
141
|
+
`references/qt/` contains 16 Qt/GObject reference documents for systematic comparison with bubus/browser-use's event-driven architecture. The full index with source URLs, per-file rationale, and bubus architecture summary is in `references/qt/README.md`.
|
|
142
|
+
|
|
143
|
+
### Reference File Map
|
|
144
|
+
|
|
145
|
+
| # | File | Topic | Compared Against (bubus/browser-use) |
|
|
146
|
+
|---|------|-------|--------------------------------------|
|
|
147
|
+
| 01 | `01_signals_and_slots.md` | Qt Signal/Slot core mechanism | `EventBus.on()` + `dispatch()` |
|
|
148
|
+
| 02 | `02_connection_type_enum.md` | 6 ConnectionType values (Auto/Direct/Queued/BlockingQueued/Unique/SingleShot) | bubus has only Queued mode |
|
|
149
|
+
| 03 | `03_qobject_connect.md` | connect/disconnect overloads, lifecycle, auto-disconnect on destruction | bubus lacks auto-disconnect |
|
|
150
|
+
| 04 | `04_event_system.md` | Event propagation chain: accept/ignore, event filters | bubus has no accept/ignore |
|
|
151
|
+
| 05 | `05_qevent.md` | QEvent class, 100+ event types, accept()/ignore() | `BaseEvent[T]` |
|
|
152
|
+
| 06 | `06_send_post_event.md` | sendEvent (sync) vs postEvent (queue) + priority | bubus only has queue (postEvent) |
|
|
153
|
+
| 07 | `07_threads_and_qobjects.md` | Thread affinity, cross-thread auto-Queued | bubus is single-threaded asyncio |
|
|
154
|
+
| 08 | `08_qeventloop.md` | Nested event loops, processEvents | bubus `inside_handler_context` polling |
|
|
155
|
+
| 09 | `09_qthread.md` | QThread, moveToThread, Worker pattern | N/A (future multi-thread consideration) |
|
|
156
|
+
| 10 | `10_event_filter.md` | installEventFilter chain, return true to stop propagation | watchdog circuit breaker (ad-hoc) |
|
|
157
|
+
| 11 | `11_property_system.md` | Q_PROPERTY + NOTIFY auto-signal on change | watchdog state change is manual dispatch |
|
|
158
|
+
| 12 | `12_state_machine.md` | QStateMachine hierarchical FSM | BrowserSession lifecycle (flag-based) |
|
|
159
|
+
| 13 | `13_meta_object_system.md` | Meta-Object System overview | bubus `dir()` + naming convention reflection |
|
|
160
|
+
| 14 | `14_moc.md` | MOC compiler: codegen vs runtime reflection | bubus runtime `on_` method scanning |
|
|
161
|
+
| 15 | `15_woboq_signal_internals.md` | Qt internals: connection list, 64-bit bitmask fast-path, O(1) cleanup | bubus handler list + WeakSet |
|
|
162
|
+
| 16 | `16_gobject_signals.md` | GObject 6-phase emission, accumulator, detail filtering | bubus `event_results` aggregation |
|
|
163
|
+
|
|
164
|
+
### Key Design Gaps Identified (bubus vs Qt)
|
|
165
|
+
|
|
166
|
+
These are the primary areas where Qt's mature design reveals potential improvements for bubus:
|
|
167
|
+
|
|
168
|
+
1. **Connection types**: bubus only supports Queued dispatch (via `asyncio.Queue`). Qt offers Direct (synchronous inline), Queued, BlockingQueued, and Auto (auto-selects based on thread affinity). Adding at least a Direct mode would enable zero-overhead handler invocation for same-context calls.
|
|
169
|
+
|
|
170
|
+
2. **Event propagation control**: bubus has no accept/ignore mechanism. Once dispatched, an event reaches all registered handlers unconditionally. Qt allows handlers to accept (consume) or ignore (pass through) events, and event filters can intercept and stop propagation before the target sees it.
|
|
171
|
+
|
|
172
|
+
3. **Event filter chain**: bubus's event interception is ad-hoc — `_would_create_loop()` and the watchdog circuit breaker wrapper are hardcoded special cases. Qt provides a general `installEventFilter()` mechanism where any object can intercept events for any other object, with LIFO ordering and return-true-to-stop semantics.
|
|
173
|
+
|
|
174
|
+
4. **Auto-disconnect on destruction**: Qt automatically severs all signal/slot connections when either sender or receiver is destroyed. bubus has no equivalent — `BaseWatchdog` has no `detach_from_session()` method, and `__del__` only cancels asyncio tasks.
|
|
175
|
+
|
|
176
|
+
5. **Handler priority**: bubus handlers execute in registration order (FIFO) with no priority mechanism. Qt's `postEvent()` accepts integer priority for queue ordering. GObject goes further with 6 emission phases (RUN_FIRST → EMISSION_HOOK → HANDLER_RUN_FIRST → RUN_LAST → HANDLER_RUN_LAST → RUN_CLEANUP).
|
|
177
|
+
|
|
178
|
+
6. **State machine for lifecycle**: BrowserSession manages connection state via boolean flags (`is_cdp_connected`, `is_reconnecting`). Qt's `QStateMachine` provides formal hierarchical state machines with signal-driven transitions, error states, and property animation — a more robust pattern for complex lifecycle management.
|
|
179
|
+
|
|
180
|
+
7. **Property change notifications**: Watchdog state changes require manual `dispatch()` calls. Qt's `Q_PROPERTY(... NOTIFY signal)` automatically emits a signal when a property changes, eliminating boilerplate.
|
|
181
|
+
|
|
182
|
+
8. **Result accumulation**: bubus has flexible result aggregation (`event_result()`, `event_results_flat_dict()`, etc.). GObject's accumulator pattern is more formalized — an accumulator function receives each handler's return value and can short-circuit emission by returning FALSE. This is worth studying for bubus's `event_results_filtered()` design.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebFetch(domain:doc.qt.io)",
|
|
5
|
+
"WebFetch(domain:woboq.com)",
|
|
6
|
+
"WebFetch(domain:docs.gtk.org)",
|
|
7
|
+
"Bash(grep:*)",
|
|
8
|
+
"Bash(wc:*)",
|
|
9
|
+
"Bash(pip show:*)",
|
|
10
|
+
"Bash(python:*)",
|
|
11
|
+
"Bash(ls:*)",
|
|
12
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog -type f -name *.lock -o -name *.toml -o -name *.md)",
|
|
13
|
+
"Bash(python3:*)",
|
|
14
|
+
"Bash(uv sync:*)",
|
|
15
|
+
"Bash(uv run:*)",
|
|
16
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/tests -type f -name *.py)",
|
|
17
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src -type f -name *.py)",
|
|
18
|
+
"Bash(find /root/.claude/projects -name *.md -type f)",
|
|
19
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src/agent_cdp -name \"*.py\" -type f -exec wc -l {} +)"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitdir: /root/QLY/code/event_driven_browser_watchdog/.git/worktrees/agent-a76c879b
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
sdist/
|
|
11
|
+
wheels/
|
|
12
|
+
*.whl
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
|
|
26
|
+
# Testing / Coverage
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Project-specific
|
|
38
|
+
bu_ref/
|
|
39
|
+
references/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This repo is an exploration workspace for browser event-driven design (browser-use edition). It contains three independent but interconnected libraries that together form a layered browser automation stack:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Agent (browser-use) ←→ EventBus (bubus) ←→ CDPClient (cdp-use) ←→ Chrome WebSocket
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The goal is to study how browser-use implements event-driven coordination across ~15 watchdog services, identify architectural strengths and gaps, and experiment with improvements.
|
|
14
|
+
|
|
15
|
+
## Repository Layout
|
|
16
|
+
|
|
17
|
+
| Directory | Package | Description |
|
|
18
|
+
|-----------|---------|-------------|
|
|
19
|
+
| `bubus/` | `bubus==1.5.6` | Pydantic-powered async event bus (pub/sub framework) |
|
|
20
|
+
| `cdp-use/` | `cdp-use==1.4.5` | Auto-generated type-safe Python bindings for Chrome DevTools Protocol |
|
|
21
|
+
| `browser-use/` | `browser-use==0.12.2` | AI browser automation agent that wires the above two together |
|
|
22
|
+
|
|
23
|
+
Each is a standalone `uv`-managed Python project with its own `.venv`, `pyproject.toml`, and test suite. For local development where browser-use depends on local bubus/cdp-use, uncomment `[tool.uv.sources]` in `browser-use/pyproject.toml`.
|
|
24
|
+
|
|
25
|
+
## Development Commands
|
|
26
|
+
|
|
27
|
+
All three use `uv` (Python >=3.11). Run commands from each package's directory.
|
|
28
|
+
|
|
29
|
+
### bubus
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd bubus
|
|
33
|
+
uv sync
|
|
34
|
+
uv run pytest -vxs tests/ # all tests
|
|
35
|
+
uv run pytest -vxs tests/test_eventbus.py # single test file
|
|
36
|
+
uv run ruff check --fix && uv run ruff format # lint + format
|
|
37
|
+
uv run pyright # type check (strict mode)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### cdp-use
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cd cdp-use
|
|
44
|
+
uv sync
|
|
45
|
+
uv run python -m cdp_use.generator # regenerate CDP types from protocol JSON
|
|
46
|
+
uv run ruff check cdp_use/ --statistics # lint
|
|
47
|
+
uv run ruff format cdp_use/ # format
|
|
48
|
+
# Or use: task generate / task lint / task format (Taskfile.yml)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### browser-use
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd browser-use
|
|
55
|
+
uv sync
|
|
56
|
+
uv run pytest -vxs tests/ci # CI test suite (default set)
|
|
57
|
+
uv run pytest -vxs tests/ci/test_foo.py # single test
|
|
58
|
+
uv run ruff check --fix && uv run ruff format # lint + format
|
|
59
|
+
uv run pyright # type check (basic mode)
|
|
60
|
+
uv run pre-commit run --all-files # all pre-commit hooks
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
### Layer 1: bubus — Event Bus
|
|
66
|
+
|
|
67
|
+
Core primitive. Provides `EventBus` and `BaseEvent[T_EventResultType]` (generic over return type).
|
|
68
|
+
|
|
69
|
+
Key capabilities: async dispatch with FIFO queue, `expect()` to await future events, event result aggregation (flat dict / list / by handler ID), handler timeouts, retry decorator with semaphore-based concurrency, event forwarding between bus instances (with loop prevention), Write-Ahead Logging for persistence, child/nested events with parent tracking.
|
|
70
|
+
|
|
71
|
+
### Layer 2: cdp-use — CDP Client
|
|
72
|
+
|
|
73
|
+
Thin typed wrapper over Chrome DevTools Protocol WebSocket. Two main pieces:
|
|
74
|
+
|
|
75
|
+
1. **Generator** (`cdp_use/generator/`) — downloads Chrome protocol JSON specs and generates Python TypedDict classes for all 50+ CDP domains (Page, Runtime, DOM, Network, Target, etc.)
|
|
76
|
+
2. **Client** (`cdp_use/client.py`) — WebSocket client exposing `cdp.send.Domain.method(params={...})` and `cdp.register.Domain.eventName(callback)` with full type safety
|
|
77
|
+
|
|
78
|
+
No event registration via `cdp.on(...)` — only `cdp.register.Domain.event(callback)`.
|
|
79
|
+
|
|
80
|
+
### Layer 3: browser-use — Agent + Watchdogs
|
|
81
|
+
|
|
82
|
+
The orchestration layer. Key architectural patterns:
|
|
83
|
+
|
|
84
|
+
**Service/Views pattern**: each component has `service.py` (logic) and `views.py` (Pydantic models).
|
|
85
|
+
|
|
86
|
+
**BrowserSession** (`browser_use/browser/session.py`) is the hub — manages CDP connections, tab lifecycle, and coordinates watchdogs through a central `EventBus`.
|
|
87
|
+
|
|
88
|
+
**Watchdog pattern** (`browser_use/browser/watchdog_base.py`): Each watchdog is a `BaseWatchdog` subclass (Pydantic model) that declares `LISTENS_TO` and `EMITS` class vars. Handlers auto-register by naming convention: `on_{EventClassName}(self, event)`.
|
|
89
|
+
|
|
90
|
+
15 watchdogs in `browser_use/browser/watchdogs/`:
|
|
91
|
+
- `dom_watchdog` — DOM snapshots, element highlighting, accessibility tree
|
|
92
|
+
- `screenshot_watchdog` — screenshot capture
|
|
93
|
+
- `downloads_watchdog` — file downloads, PDF auto-download
|
|
94
|
+
- `popups_watchdog` — JS dialogs
|
|
95
|
+
- `security_watchdog` — domain restrictions
|
|
96
|
+
- `aboutblank_watchdog` — empty page handling
|
|
97
|
+
- `local_browser_watchdog` — local Chrome process lifecycle
|
|
98
|
+
- `permissions_watchdog` — browser permissions
|
|
99
|
+
- `crash_watchdog` — target crash monitoring
|
|
100
|
+
- `storage_state_watchdog` — cookie/localStorage persistence
|
|
101
|
+
- `captcha_watchdog` — CAPTCHA solver integration
|
|
102
|
+
- `har_recording_watchdog` — network recording (HAR)
|
|
103
|
+
- `recording_watchdog` — browser automation recording
|
|
104
|
+
- `default_action_watchdog` — default action handlers
|
|
105
|
+
|
|
106
|
+
**Events** (`browser_use/browser/events.py`): All events inherit `BaseEvent[T]`. Two categories:
|
|
107
|
+
- Action events (Agent → Browser): `NavigateToUrlEvent`, `ClickElementEvent`, `TypeTextEvent`, `ScreenshotEvent`, `BrowserStartEvent`, etc.
|
|
108
|
+
- Notification events (Browser → Agent/Watchdogs): `BrowserConnectedEvent`, `TabCreatedEvent`, `NavigationCompleteEvent`, `DownloadStartedEvent`, `DialogOpenedEvent`, etc.
|
|
109
|
+
|
|
110
|
+
Event timeouts are configurable via environment variables (`TIMEOUT_NavigateToUrlEvent`, etc.).
|
|
111
|
+
|
|
112
|
+
## Code Style Differences
|
|
113
|
+
|
|
114
|
+
| | bubus | cdp-use | browser-use |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| Indent | spaces | (generated) | **tabs** |
|
|
117
|
+
| Quotes | single | — | single |
|
|
118
|
+
| pyright | strict | — | basic |
|
|
119
|
+
| Line length | 130 | — | 130 |
|
|
120
|
+
|
|
121
|
+
browser-use uses **tabs** for indentation. bubus uses **spaces**. Both use single quotes and ruff for linting/formatting.
|
|
122
|
+
|
|
123
|
+
## Testing Conventions (browser-use)
|
|
124
|
+
|
|
125
|
+
- Tests that pass go into `tests/ci/` — this is the CI-discovered default set
|
|
126
|
+
- **No mocking** except for LLM responses (use `conftest.py` fixtures for LLM mocking)
|
|
127
|
+
- Use `pytest-httpserver` for all test HTML/responses — never use real remote URLs
|
|
128
|
+
- Modern pytest-asyncio: no `@pytest.mark.asyncio` decorator needed, just write `async def test_*()`
|
|
129
|
+
- `asyncio_mode = "auto"` with session-scoped event loop (browser-use) or function-scoped (bubus)
|
|
130
|
+
|
|
131
|
+
## Key Design Decisions to Be Aware Of
|
|
132
|
+
|
|
133
|
+
1. **Shared state belongs on BrowserSession, not on individual watchdogs.** Watchdogs expose state/helpers via events if other watchdogs need access.
|
|
134
|
+
2. **CDP event forwarding**: BrowserSession forwards raw CDP events to watchdogs through the EventBus, not direct CDP callbacks.
|
|
135
|
+
3. **BaseEvent is generic over result type** (`BaseEvent[T_EventResultType]`) — dispatchers can aggregate results from multiple handlers via `event.event_result()`, `event.event_results_list()`, etc.
|
|
136
|
+
4. **Lazy imports** in `browser_use/__init__.py` for startup performance.
|
|
137
|
+
5. **browser-use has its own CLAUDE.md** (`browser-use/CLAUDE.md`) with detailed per-package conventions — read it when working inside browser-use specifically.
|
|
138
|
+
|
|
139
|
+
## Qt Reference Materials
|
|
140
|
+
|
|
141
|
+
`references/qt/` contains 16 Qt/GObject reference documents for systematic comparison with bubus/browser-use's event-driven architecture. The full index with source URLs, per-file rationale, and bubus architecture summary is in `references/qt/README.md`.
|
|
142
|
+
|
|
143
|
+
### Reference File Map
|
|
144
|
+
|
|
145
|
+
| # | File | Topic | Compared Against (bubus/browser-use) |
|
|
146
|
+
|---|------|-------|--------------------------------------|
|
|
147
|
+
| 01 | `01_signals_and_slots.md` | Qt Signal/Slot core mechanism | `EventBus.on()` + `dispatch()` |
|
|
148
|
+
| 02 | `02_connection_type_enum.md` | 6 ConnectionType values (Auto/Direct/Queued/BlockingQueued/Unique/SingleShot) | bubus has only Queued mode |
|
|
149
|
+
| 03 | `03_qobject_connect.md` | connect/disconnect overloads, lifecycle, auto-disconnect on destruction | bubus lacks auto-disconnect |
|
|
150
|
+
| 04 | `04_event_system.md` | Event propagation chain: accept/ignore, event filters | bubus has no accept/ignore |
|
|
151
|
+
| 05 | `05_qevent.md` | QEvent class, 100+ event types, accept()/ignore() | `BaseEvent[T]` |
|
|
152
|
+
| 06 | `06_send_post_event.md` | sendEvent (sync) vs postEvent (queue) + priority | bubus only has queue (postEvent) |
|
|
153
|
+
| 07 | `07_threads_and_qobjects.md` | Thread affinity, cross-thread auto-Queued | bubus is single-threaded asyncio |
|
|
154
|
+
| 08 | `08_qeventloop.md` | Nested event loops, processEvents | bubus `inside_handler_context` polling |
|
|
155
|
+
| 09 | `09_qthread.md` | QThread, moveToThread, Worker pattern | N/A (future multi-thread consideration) |
|
|
156
|
+
| 10 | `10_event_filter.md` | installEventFilter chain, return true to stop propagation | watchdog circuit breaker (ad-hoc) |
|
|
157
|
+
| 11 | `11_property_system.md` | Q_PROPERTY + NOTIFY auto-signal on change | watchdog state change is manual dispatch |
|
|
158
|
+
| 12 | `12_state_machine.md` | QStateMachine hierarchical FSM | BrowserSession lifecycle (flag-based) |
|
|
159
|
+
| 13 | `13_meta_object_system.md` | Meta-Object System overview | bubus `dir()` + naming convention reflection |
|
|
160
|
+
| 14 | `14_moc.md` | MOC compiler: codegen vs runtime reflection | bubus runtime `on_` method scanning |
|
|
161
|
+
| 15 | `15_woboq_signal_internals.md` | Qt internals: connection list, 64-bit bitmask fast-path, O(1) cleanup | bubus handler list + WeakSet |
|
|
162
|
+
| 16 | `16_gobject_signals.md` | GObject 6-phase emission, accumulator, detail filtering | bubus `event_results` aggregation |
|
|
163
|
+
|
|
164
|
+
### Key Design Gaps Identified (bubus vs Qt)
|
|
165
|
+
|
|
166
|
+
These are the primary areas where Qt's mature design reveals potential improvements for bubus:
|
|
167
|
+
|
|
168
|
+
1. **Connection types**: bubus only supports Queued dispatch (via `asyncio.Queue`). Qt offers Direct (synchronous inline), Queued, BlockingQueued, and Auto (auto-selects based on thread affinity). Adding at least a Direct mode would enable zero-overhead handler invocation for same-context calls.
|
|
169
|
+
|
|
170
|
+
2. **Event propagation control**: bubus has no accept/ignore mechanism. Once dispatched, an event reaches all registered handlers unconditionally. Qt allows handlers to accept (consume) or ignore (pass through) events, and event filters can intercept and stop propagation before the target sees it.
|
|
171
|
+
|
|
172
|
+
3. **Event filter chain**: bubus's event interception is ad-hoc — `_would_create_loop()` and the watchdog circuit breaker wrapper are hardcoded special cases. Qt provides a general `installEventFilter()` mechanism where any object can intercept events for any other object, with LIFO ordering and return-true-to-stop semantics.
|
|
173
|
+
|
|
174
|
+
4. **Auto-disconnect on destruction**: Qt automatically severs all signal/slot connections when either sender or receiver is destroyed. bubus has no equivalent — `BaseWatchdog` has no `detach_from_session()` method, and `__del__` only cancels asyncio tasks.
|
|
175
|
+
|
|
176
|
+
5. **Handler priority**: bubus handlers execute in registration order (FIFO) with no priority mechanism. Qt's `postEvent()` accepts integer priority for queue ordering. GObject goes further with 6 emission phases (RUN_FIRST → EMISSION_HOOK → HANDLER_RUN_FIRST → RUN_LAST → HANDLER_RUN_LAST → RUN_CLEANUP).
|
|
177
|
+
|
|
178
|
+
6. **State machine for lifecycle**: BrowserSession manages connection state via boolean flags (`is_cdp_connected`, `is_reconnecting`). Qt's `QStateMachine` provides formal hierarchical state machines with signal-driven transitions, error states, and property animation — a more robust pattern for complex lifecycle management.
|
|
179
|
+
|
|
180
|
+
7. **Property change notifications**: Watchdog state changes require manual `dispatch()` calls. Qt's `Q_PROPERTY(... NOTIFY signal)` automatically emits a signal when a property changes, eliminating boilerplate.
|
|
181
|
+
|
|
182
|
+
8. **Result accumulation**: bubus has flexible result aggregation (`event_result()`, `event_results_flat_dict()`, etc.). GObject's accumulator pattern is more formalized — an accumulator function receives each handler's return value and can short-circuit emission by returning FALSE. This is worth studying for bubus's `event_results_filtered()` design.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebFetch(domain:doc.qt.io)",
|
|
5
|
+
"WebFetch(domain:woboq.com)",
|
|
6
|
+
"WebFetch(domain:docs.gtk.org)",
|
|
7
|
+
"Bash(grep:*)",
|
|
8
|
+
"Bash(wc:*)",
|
|
9
|
+
"Bash(pip show:*)",
|
|
10
|
+
"Bash(python:*)",
|
|
11
|
+
"Bash(ls:*)",
|
|
12
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog -type f -name *.lock -o -name *.toml -o -name *.md)",
|
|
13
|
+
"Bash(python3:*)",
|
|
14
|
+
"Bash(uv sync:*)",
|
|
15
|
+
"Bash(uv run:*)",
|
|
16
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/tests -type f -name *.py)",
|
|
17
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src -type f -name *.py)",
|
|
18
|
+
"Bash(find /root/.claude/projects -name *.md -type f)",
|
|
19
|
+
"Bash(find /root/QLY/code/event_driven_browser_watchdog/src/agent_cdp -name \"*.py\" -type f -exec wc -l {} +)"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitdir: /root/QLY/code/event_driven_browser_watchdog/.git/worktrees/agent-aaf55f3e
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
sdist/
|
|
11
|
+
wheels/
|
|
12
|
+
*.whl
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
|
|
26
|
+
# Testing / Coverage
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Project-specific
|
|
38
|
+
bu_ref/
|
|
39
|
+
references/
|