browserwright 0.6.2__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.
- browserwright/__init__.py +33 -0
- browserwright/__main__.py +6 -0
- browserwright/_executor/__init__.py +47 -0
- browserwright/_executor/__main__.py +9 -0
- browserwright/_executor/client.py +127 -0
- browserwright/_executor/process.py +652 -0
- browserwright/_executor/protocol.py +152 -0
- browserwright/api.py +66 -0
- browserwright/cdp.py +285 -0
- browserwright/cli.py +741 -0
- browserwright/daemon/__init__.py +8 -0
- browserwright/daemon/_ipc.py +444 -0
- browserwright/daemon/active_tab.py +183 -0
- browserwright/daemon/auth.py +395 -0
- browserwright/daemon/backends/__init__.py +59 -0
- browserwright/daemon/backends/base.py +120 -0
- browserwright/daemon/backends/cloud.py +222 -0
- browserwright/daemon/backends/env.py +119 -0
- browserwright/daemon/backends/extension.py +185 -0
- browserwright/daemon/backends/rdp.py +214 -0
- browserwright/daemon/cli.py +1437 -0
- browserwright/daemon/config.py +380 -0
- browserwright/daemon/doctor.py +179 -0
- browserwright/daemon/errors.py +34 -0
- browserwright/daemon/launch_chrome.py +353 -0
- browserwright/daemon/observability.py +181 -0
- browserwright/daemon/platforms.py +234 -0
- browserwright/daemon/resolver.py +72 -0
- browserwright/daemon/server/__init__.py +6 -0
- browserwright/daemon/server/daemon.py +229 -0
- browserwright/daemon/server/executor_registry.py +434 -0
- browserwright/daemon/server/extension_upstream.py +677 -0
- browserwright/daemon/server/facade.py +375 -0
- browserwright/daemon/server/facade_extension.py +969 -0
- browserwright/daemon/server/listener.py +1058 -0
- browserwright/daemon/server/proxy.py +1991 -0
- browserwright/daemon/server/relay.py +783 -0
- browserwright/daemon/server/state.py +432 -0
- browserwright/daemon/server/upstream.py +266 -0
- browserwright/daemon/userscripts.py +150 -0
- browserwright/discovery.py +213 -0
- browserwright/errors.py +177 -0
- browserwright/health.py +169 -0
- browserwright/install.py +628 -0
- browserwright/memory/__init__.py +15 -0
- browserwright/memory/_md.py +120 -0
- browserwright/memory/_yaml.py +217 -0
- browserwright/memory/global_mem.py +201 -0
- browserwright/memory/repl_mem.py +28 -0
- browserwright/memory/session_decisions.py +53 -0
- browserwright/memory/site_mem.py +381 -0
- browserwright/mode_b_client.py +590 -0
- browserwright/multitask.py +131 -0
- browserwright/output_schema.py +99 -0
- browserwright/primitives/__init__.py +67 -0
- browserwright/primitives/discovery_api.py +79 -0
- browserwright/primitives/http.py +42 -0
- browserwright/primitives/inspect.py +876 -0
- browserwright/primitives/interact.py +518 -0
- browserwright/primitives/page.py +556 -0
- browserwright/primitives/site.py +143 -0
- browserwright/release_install.py +466 -0
- browserwright/repl/__init__.py +6 -0
- browserwright/repl/_namespace.py +106 -0
- browserwright/repl/_smart_goto.py +236 -0
- browserwright/repl/inline.py +180 -0
- browserwright/repl/playwright_handle.py +449 -0
- browserwright/repl/snapshot.py +150 -0
- browserwright/session.py +229 -0
- browserwright/session_create.py +252 -0
- browserwright/session_ctx.py +24 -0
- browserwright/session_registry.py +133 -0
- browserwright/session_runtime.py +133 -0
- browserwright/site_skills_starter/github.com/SKILL.md +14 -0
- browserwright/site_skills_starter/github.com/memory.md +29 -0
- browserwright/site_skills_starter/github.com/tasks/list_issues.py +55 -0
- browserwright/site_skills_starter/google.com/SKILL.md +16 -0
- browserwright/site_skills_starter/google.com/memory.md +27 -0
- browserwright/site_skills_starter/google.com/tasks/search.py +53 -0
- browserwright/site_skills_starter/producthunt.com/SKILL.md +7 -0
- browserwright/site_skills_starter/producthunt.com/memory.md +26 -0
- browserwright/site_skills_starter/producthunt.com/tasks/today.py +64 -0
- browserwright/site_skills_starter/wikipedia.org/SKILL.md +7 -0
- browserwright/site_skills_starter/wikipedia.org/memory.md +22 -0
- browserwright/site_skills_starter/wikipedia.org/tasks/lookup.py +55 -0
- browserwright/site_skills_starter/ycombinator.com/SKILL.md +8 -0
- browserwright/site_skills_starter/ycombinator.com/memory.md +25 -0
- browserwright/site_skills_starter/ycombinator.com/tasks/front_page.py +63 -0
- browserwright/skill_doc.py +140 -0
- browserwright/skill_runtime.md +194 -0
- browserwright/subscriptions.py +213 -0
- browserwright/task_runner.py +125 -0
- browserwright/version.py +117 -0
- browserwright-0.6.2.dist-info/METADATA +12 -0
- browserwright-0.6.2.dist-info/RECORD +98 -0
- browserwright-0.6.2.dist-info/WHEEL +5 -0
- browserwright-0.6.2.dist-info/entry_points.txt +3 -0
- browserwright-0.6.2.dist-info/top_level.txt +1 -0
browserwright/health.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Skill-side health: forward ``browserwright-daemon doctor`` and derive an
|
|
2
|
+
actionable ``{status, message, fix}`` check table (A4).
|
|
3
|
+
|
|
4
|
+
This is **not** a CDP driving path — it shells out to the daemon's standalone
|
|
5
|
+
``doctor`` subcommand (zero ws side effects, spec H3) and transforms the blob.
|
|
6
|
+
It lived on the old Mode A ``DaemonClient`` historically; it has no dependency
|
|
7
|
+
on Mode A and stays after Mode A's removal. Consumed by ``browserwright doctor``
|
|
8
|
+
(``cli.py``) and the install wizard's option-availability probe (``install.py``).
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import subprocess
|
|
14
|
+
|
|
15
|
+
# Doctor blobs this browserwright build knows how to read. The daemon's current
|
|
16
|
+
# contract is v2 (bumped in daemon v0.5.3); v1 is still parseable for the fields
|
|
17
|
+
# we use. Anything else = real version skew.
|
|
18
|
+
_SUPPORTED_DOCTOR_SCHEMAS = (1, 2)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def daemon_doctor() -> dict:
|
|
22
|
+
"""Forward ``browserwright-daemon doctor --json``. Always returns a dict; on
|
|
23
|
+
failure returns a synthetic ``schema_version:1`` blob explaining why."""
|
|
24
|
+
cmd = ["browserwright-daemon", "doctor", "--json"]
|
|
25
|
+
try:
|
|
26
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
|
27
|
+
except (FileNotFoundError, subprocess.TimeoutExpired) as e:
|
|
28
|
+
return {
|
|
29
|
+
"schema_version": 1,
|
|
30
|
+
"backends": [],
|
|
31
|
+
"error": str(e),
|
|
32
|
+
"skill_synthetic": True,
|
|
33
|
+
}
|
|
34
|
+
if proc.returncode != 0:
|
|
35
|
+
return {
|
|
36
|
+
"schema_version": 1,
|
|
37
|
+
"backends": [],
|
|
38
|
+
"error": (proc.stderr or proc.stdout or "").strip(),
|
|
39
|
+
"skill_synthetic": True,
|
|
40
|
+
"exit_code": proc.returncode,
|
|
41
|
+
}
|
|
42
|
+
try:
|
|
43
|
+
return json.loads(proc.stdout)
|
|
44
|
+
except json.JSONDecodeError:
|
|
45
|
+
return {
|
|
46
|
+
"schema_version": 1,
|
|
47
|
+
"backends": [],
|
|
48
|
+
"error": "doctor output was not JSON",
|
|
49
|
+
"skill_synthetic": True,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def doctor_checks() -> dict:
|
|
54
|
+
"""Derive an actionable ``{status, message, fix}`` check table from the raw
|
|
55
|
+
``daemon_doctor()`` blob (A4).
|
|
56
|
+
|
|
57
|
+
Each check is ``{"name", "status", "message", "fix"}`` where status is one
|
|
58
|
+
of ``pass`` / ``warn`` / ``fail``. The discipline (enforced by the gate
|
|
59
|
+
test): **every ``fail`` check carries a non-empty ``fix``**. The ``fix`` for
|
|
60
|
+
non-fail checks is the empty string.
|
|
61
|
+
|
|
62
|
+
This is a pure transform over the daemon blob plus a couple of local probes
|
|
63
|
+
(helper-module parse), so it stays deterministic and testable without a live
|
|
64
|
+
browser. Checks whose ground truth needs a live daemon / extension degrade
|
|
65
|
+
to ``warn`` rather than asserting health they can't observe.
|
|
66
|
+
"""
|
|
67
|
+
info = daemon_doctor()
|
|
68
|
+
checks: list[dict] = []
|
|
69
|
+
|
|
70
|
+
def add(name, status, message, fix=""):
|
|
71
|
+
# Invariant: a fail must always ship a recovery action.
|
|
72
|
+
if status == "fail" and not (fix and fix.strip()):
|
|
73
|
+
fix = "run `browserwright doctor` and address the first failing check"
|
|
74
|
+
checks.append({"name": name, "status": status,
|
|
75
|
+
"message": message, "fix": fix})
|
|
76
|
+
|
|
77
|
+
# 1. daemon reachable (did `browserwright-daemon doctor` actually answer?)
|
|
78
|
+
if info.get("skill_synthetic"):
|
|
79
|
+
add(
|
|
80
|
+
"daemon",
|
|
81
|
+
"fail",
|
|
82
|
+
info.get("error") or "browserwright-daemon did not respond",
|
|
83
|
+
"install/start the daemon: ensure `browserwright-daemon` is on PATH "
|
|
84
|
+
"then `browserwright-daemon serve`",
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
add("daemon", "pass", "browserwright-daemon responded to doctor", "")
|
|
88
|
+
|
|
89
|
+
# 2. schema version sanity (catches a daemon too old to speak the blob)
|
|
90
|
+
sv = info.get("schema_version")
|
|
91
|
+
if not info.get("skill_synthetic"):
|
|
92
|
+
if sv in _SUPPORTED_DOCTOR_SCHEMAS:
|
|
93
|
+
add("daemon_schema", "pass", f"doctor schema_version={sv}", "")
|
|
94
|
+
else:
|
|
95
|
+
add(
|
|
96
|
+
"daemon_schema",
|
|
97
|
+
"warn",
|
|
98
|
+
f"unexpected doctor schema_version={sv!r}",
|
|
99
|
+
"update browserwright-daemon and browserwright to matching versions",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# 3. at least one usable backend (relay/extension/rdp connection probe)
|
|
103
|
+
backends = info.get("backends") or []
|
|
104
|
+
usable = [b for b in backends if b.get("available")]
|
|
105
|
+
if not info.get("skill_synthetic"):
|
|
106
|
+
if usable:
|
|
107
|
+
names = ", ".join(b.get("name", "?") for b in usable)
|
|
108
|
+
add("backend", "pass", f"available backend(s): {names}", "")
|
|
109
|
+
elif backends:
|
|
110
|
+
# backends exist but none available — surface each one's hint.
|
|
111
|
+
hints = [b.get("needs_user_action") for b in backends
|
|
112
|
+
if b.get("needs_user_action")]
|
|
113
|
+
add(
|
|
114
|
+
"backend",
|
|
115
|
+
"fail",
|
|
116
|
+
"no backend is available "
|
|
117
|
+
f"(saw: {', '.join(b.get('name', '?') for b in backends)})",
|
|
118
|
+
"; ".join(hints) if hints else
|
|
119
|
+
"connect the extension (load unpacked) or start an rdp Chrome, "
|
|
120
|
+
"then re-run doctor",
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
add(
|
|
124
|
+
"backend",
|
|
125
|
+
"fail",
|
|
126
|
+
"daemon reported no backends",
|
|
127
|
+
"start a backend: load the extension or "
|
|
128
|
+
"create an rdp session after `browserwright-daemon serve`",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# 4. extension/relay specific: if an extension backend exists but is
|
|
132
|
+
# unavailable, call it out as its own actionable check.
|
|
133
|
+
ext = next((b for b in backends if b.get("name") == "extension"), None)
|
|
134
|
+
if ext is not None:
|
|
135
|
+
if ext.get("available"):
|
|
136
|
+
add("extension", "pass",
|
|
137
|
+
f"extension connected (ws={ext.get('ws_url', '')})", "")
|
|
138
|
+
else:
|
|
139
|
+
add(
|
|
140
|
+
"extension",
|
|
141
|
+
"warn",
|
|
142
|
+
ext.get("ux_warning") or "extension backend present but not connected",
|
|
143
|
+
ext.get("needs_user_action")
|
|
144
|
+
or "open Chrome and load the unpacked extension, then re-run doctor",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# 5. helper surface parses (local, deterministic): can we import the
|
|
148
|
+
# primitive surface agents actually call? A broken install / syntax
|
|
149
|
+
# error here would otherwise only show up mid-task.
|
|
150
|
+
try:
|
|
151
|
+
from . import api as _api # noqa: F401
|
|
152
|
+
n = len(getattr(_api, "EXPORTS", []) or [])
|
|
153
|
+
add("helpers", "pass", f"helper surface imports ({n} exports)", "")
|
|
154
|
+
except Exception as e: # noqa: BLE001
|
|
155
|
+
add(
|
|
156
|
+
"helpers",
|
|
157
|
+
"fail",
|
|
158
|
+
f"helper surface failed to import: {e!r}",
|
|
159
|
+
"reinstall browserwright (`browserwright install`) or check the "
|
|
160
|
+
"traceback above for a syntax/dependency error",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
any_fail = any(c["status"] == "fail" for c in checks)
|
|
164
|
+
return {
|
|
165
|
+
"schema_version": 1,
|
|
166
|
+
"ok": not any_fail,
|
|
167
|
+
"checks": checks,
|
|
168
|
+
"raw": info,
|
|
169
|
+
}
|