Agent held the same Browser/Session/Notification/registry fields and
teardown order as mcp/Server.zig, plus its own "enableConsoleCapture
after every newSession" for /reset. ToolSession.restartSession() owns
that now; init is written in terms of it.
Claude-Session: https://claude.ai/code/session_01M6WGk8wZSE28efFQkYT9SK
Two sessions on one thread, each entered only around its own use, with
JS state proving the isolates are separate and a balanced park/enter/
deinit teardown. Pins what the C API relies on without Server in the loop.
Claude-Session: https://claude.ai/code/session_01M6WGk8wZSE28efFQkYT9SK
stdio kept the isolate permanently entered while HTTP parked it between
requests, so a handler touching page JS without enterIsolate passed the
stdio-mode tests and only failed under --port. Bracket unconditionally:
stdio is the one-isolate case of the same discipline.
The flag survives only as `multi_session`, which is what it always gated:
the session tools need a transport that routes by id.
Claude-Session: https://claude.ai/code/session_01M6WGk8wZSE28efFQkYT9SK
Extract the Browser+Session+Notification+node Registry quartet, with its
ordering-sensitive init/teardown and isolate enter/exit, into
src/ToolSession.zig. mcp/Server.zig's sessions map now holds
*lp.ToolSession directly; the session id lives only as the map key.
Claude-Session: https://claude.ai/code/session_01M6WGk8wZSE28efFQkYT9SK
Mimic's https://github.com/lightpanda-io/browser/pull/3294
I looked into this a little bit, and the main issue is that we build the binary
in releasefast twice: once for the snapshot and once for the browser itself.
Each build takes ~10 minutes.
The snapshot cache almost always misses (since any change to webapi/*
invalidates it). I don't see a great solution.
Review feedback: markdown caps its own output through Opts.max_bytes while
the html dump left it to each caller, so the html tool and fetch each
carried a copy of the LimitedWriter wrapping. root and deep now do it,
with a no-cap fast path so innerHTML/outerHTML are unaffected.
A wait failure on one URL aborted the whole multi-URL fetch with no
output, the wait_ms budget was computed once before the loop so N pages
could take N times the budget, navigation failures exited 0 with an empty
dump, and HTTP 4xx/5xx were indistinguishable from success by exit code.
Each page now has its own error slot: wait, navigation and dump failures
are recorded there instead of returned, every page is still written (the
JSON envelope carries the name under "error"), then the first failure is
returned so the process exits 1. The remaining budget is recomputed per
page. --fail-on-http-error turns a status >= 400 into exit 22, curl's
code for the same condition; the dump is written first either way.
--strip-mode was silently ignored for --dump markdown, and fetch had no
way to scope a dump to one element or cap its size although the markdown
and html tools have both.
--selector dumps the first matching element in any dump mode, --max-bytes
caps html and markdown with the tools' truncation marker, and markdown
now honors strip ui (images; scripts, styles and hidden elements are
never rendered, so the other groups don't apply).
The links tool returned every a[href] verbatim: hidden nav entries,
one row per duplicate href, and null text for image and icon links even
though markdown already knows to use alt. Nav-heavy pages produced
thousands of rows for an agent looking for one link.
One entry per resolved href (the first, upgraded with text from a later
duplicate), hidden anchors skipped with the same check tree uses, text
falling back to aria-label, title, then a descendant img alt. The tool
gains an optional limit.
Our `Arena` from the `ArenaPool` now tracks if it's already been released. On
a subsequent release, it panics then and there. Without this, the code will
almost certainly panic anyways, but it will panic in a seemingly unrelated
place. Hopefully this makes identifying future cases of this easier (since we'll
get the stack trace of the re-releaser).
Fix 3 separate memory issues, all edge cases.
1 - an XHR error handler that re-open/sends would incorrectly null the new
transfer (maybe this isn't that odd, maybe it's a common retry-on-error).
2 - On a curl_easy_pause error (from WebSocket.zig) we now unqueue the just-
queued message, because the error will errdefer the message arena to be
cleaned up.
3 - ScriptManager now cleans up after itself on a failure prior to submit()
being called.
A worker gets a distinct Navigator type (WorkerNavigator) which only exposes
a subset of what Navigator does.
Previously, we achieved this by exposing Navigator but with a bunch of accessors
/ functions with .{.exposed = .window}. That worked fine, except the type name
was still "Navigator". This introduces an actual WorkerNavigator.
The Page now tracks the element currently being hovered. We need to track this
so that subsequent mouse events can fire the correct events. This is largely a
WebDriver (WPT) change, but it's also triggered from CDP's
`input.dispatchMouseEvent`.
So, for example, if CDP `dispatchMouseEvent` with a mouseMoved to element1
we'll fire a mouseenter. If the same command is issue for the same element, we
should NOT trigger a mouseout and mouseenter.
This has been on my TODO for a long time. https://github.com/lightpanda-io/browser/pull/3238
added support for the @@iterator protocol and now URLSearchParams' init can
use it.
We used to only support a v8::Array, but now any type that implements the
@@iterator protocol can be passed into URLSearchParams.
This also fixes and simplifies the js.Object iterator. It now yields name +
value (so callers don't need to get the name then lookup the value). But it
isn't just about making it easier to use. The name can be a lossy UTF-8
conversion, so the value lookup can fail. By internalizing the value lookup we
can use the v8::String directly for the lookup.
Fixes a handful of WPT /url/ cases
Review feedback: navigation writes cookies and storage and a wait lets page
scripts mutate state, so neither can be auto-approved as read-only.
consoleLogs drains its buffer, so repeated calls differ.
Since all children of an invisible element are skipped, the visibility cache
serves no purpose AND we can assume that any element we do visit has a visible
parent and thus just need to check the element's own visibility.
interactiveElements and findElement returned elements under display:none
or [hidden], so agents were offered controls no user could reach and the
list disagreed with tree, which already filters on visibility. Reuse the
same cached check and skip the hidden subtree.