Commit Graph

123 Commits

Author SHA1 Message Date
Nikolay Govorov
9a312a4177 Refactor server/client/cdp structure 2026-05-04 16:41:22 +01:00
Pierre Tachoire
acdddb7ec8 keep the existing page active until the pending one is loaded
During a root navigation, we keep the existing page active until we get
the headers callback from the pending page. Then
Session.commitPendingPage makes the switch.

It delays the deinit of CPD execution context to handle JS execution in
the meantime.

Now session has an array of two pages, _active_idx points to the main
page.

Both active and pending pages share the same frame_id, it must remains
stable. So this PR adds a Request.protect_from_abort to avoid removing
the request form the pending page when deinit the previous active page.
2026-05-04 08:50:26 +02:00
Karl Seguin
550fb58f3f Introduce Page (container)
Follow up to https://github.com/lightpanda-io/browser/pull/2200

This change is actually pretty mundane, but a bunch of files that used to
take a *Session (e.g. every WebAPI releaseRef and deinit) now take a *Page.

This aims to separate the 2 lifetimes currently managed by Session by moving
the "Page" lifetime to a dedicated container: Page. Ultimately, the goal is to
remove the 1-page-per-session limit of the current design. Not to explicitly
support multiple pages per session (though, that's more possible now), but
in order to better emulate Chrome where, during a navigation event, the old and
new page both exist.
2026-04-23 15:48:13 +08:00
Karl Seguin
2275416505 Page -> Frame
This is to pave the way for introducing a new "Page" container, which will take
over the page lifecycle currently burdening Session. The ultimate goal of that
is to allow the Session to have multiple pages (mostly for better transitions
between pages), which is hard to do now since the Session has so much state.

This rename was aggressive, e.g. currentPage() -> currentFrame() so that, when
the new Page container is added, you won't see "currentPage()" and wonder:

  "Does 'currentPage' mean the new Page container, or the Frame (which
  used to be called Page)".
2026-04-22 08:42:18 +08:00
Karl Seguin
2d20e57f80 Change all @import("...../log.zig") to const log = lp.log;
@import("lightpanda") where needed.

Would also like to do this for String, Page, Session and js which all stand out
as types that are use across the codebase.

I know that a few devs are doing this in new work and I haven't heard anyone
voice an objection.
2026-04-20 12:40:04 +08:00
Karl Seguin
3ca1f230b9 Serialize sameSite
Tweak ergonomics (public functions log internally and are infallible). Use
readFileAlloc directly. Fix possible memory leak with cookie arena - I don't
think you can make a copy of the arena, and then dupe with the original.
2026-04-16 10:35:34 +08:00
Pierre Tachoire
a24fcc6a5c use session arg to load cookies from file 2026-04-15 10:29:53 -04:00
Matt Van Horn
35991a1b32 refactor: split --cookies-file into --cookie/--cookie-jar per curl convention
Split the single --cookies-file flag into two flags following curl's
convention as requested by @krichprollsch:

- --cookie (read-only): loads cookies at startup for fetch, mcp, and
  serve/CDP commands
- --cookie-jar (write-only): saves cookies on exit for fetch and mcp
  only (CDP cookie-jar deferred per maintainer guidance)

Add cookie integration to MCP server (load in init, save in deinit)
and CDP session creation (load only). The serve command now rejects
--cookie-jar with a clear error message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:09:13 -04:00
Adrià Arrufat
afd6c11b34 Config: remove mcp version flag and simplify usage 2026-04-07 12:24:19 +02:00
Adrià Arrufat
72229f715a Merge branch 'main' into mcp-new-action-tools 2026-04-03 07:06:10 +02:00
Adrià Arrufat
62f58b4c12 browser: treat wait timeout as normal completion, not an error 2026-04-02 14:54:06 +02:00
Adrià Arrufat
6c9a5ddab8 Extract shared helpers to reduce duplication
- Extract dispatchInputAndChangeEvents() in actions.zig, used by fill,
  selectOption, and setChecked
- Extract resolveNodeAndPage() in tools.zig, used by click, fill, hover,
  selectOption, setChecked, and nodeDetails handlers
2026-04-02 11:20:28 +02:00
Adrià Arrufat
46a63e0b4b Add focus before fill and findElement MCP tool
- fill action now calls focus() on the element before setting its value,
  ensuring focus/focusin events fire for JS listeners
- Add findElement MCP tool for locating interactive elements by ARIA role
  and/or accessible name (case-insensitive substring match)
- Add tests for findElement (by role, by name, no matches, missing params)
2026-04-02 11:03:49 +02:00
Adrià Arrufat
58143ee3d1 Fix event order and add tests
- Fix setChecked event order: click fires before input/change to match
  browser behavior
- Add tests for hover, press, selectOption, setChecked MCP tools
- Merge all action tests into a single test case sharing one page load
- Add test elements to mcp_actions.html (hover target, key input,
  second select, checkbox, radio)
2026-04-02 10:46:28 +02:00
Adrià Arrufat
5e79af42f4 mcp: Add hover, press, selectOption, setChecked
New browser actions and MCP tools for AI agent interaction:
- hover: dispatches mouseover/mouseenter events on an element
- press: dispatches keydown/keyup keyboard events (Enter, Tab, etc.)
- selectOption: selects a dropdown option by value with input/change events
- setChecked: checks/unchecks checkbox or radio with input/change/click events
2026-04-02 09:47:22 +02:00
Adrià Arrufat
1854627b69 mcp: final protocol cleanup after removing screenshot tool
- Removed unused ImageContent from protocol.
- Simplified CallToolResult back to only support TextContent.
- Cleaned up CallToolResult usages in tools.zig.
2026-04-01 15:00:55 +02:00
Adrià Arrufat
fffa8b6d4b mcp/cdp: fix inactivity timeout
- Fixed CDP inactivity timeout by resetting it when the browser is busy (loading or executing macrotasks).
- Removed the placeholder screenshot tool.
- Refactored MCP tool schemas to constants to avoid duplication.
2026-04-01 14:37:40 +02:00
Adrià Arrufat
58fc60d669 mcp: improve navigation reliability and add CDP support
- Configurable navigation timeouts and wait strategies in MCP tools.
- Default navigation timeout increased from 2s to 10s.
- Added navigate, eval, and screenshot MCP tools.
- Supported running a CDP server alongside MCP using --cdp-port.
- Fixed various startup crashes when running CDP in MCP mode.
- Hardened MCP server error handling.
2026-04-01 12:41:56 +02:00
Adrià Arrufat
008235222b SemanticTree: reorder getNodeDetails params 2026-03-31 07:29:33 +02:00
Adrià Arrufat
9c8fe9b20f SemanticTree: Add nodeDetails tool
Adds a tool to retrieve detailed node metadata and updates the
semantic tree to track and display the disabled state of elements.
2026-03-30 16:38:23 +02:00
Adrià Arrufat
20e62a5551 mcp: inline mcpVersion helper from Config 2026-03-30 07:13:45 +02:00
Adrià Arrufat
81d4bdb157 mcp: change default protocol version to 2024-11-05 2026-03-29 08:34:24 +02:00
Adrià Arrufat
cf5e4d7d1e mcp: allow configuring protocol version
Closes #2023
2026-03-29 08:29:04 +02:00
Karl Seguin
67bd555e75 Merge pull request #2013 from lightpanda-io/cleanup_dead_code_removal
Remove unused imports
2026-03-27 13:52:49 +08:00
Adrià Arrufat
a10e533701 Remove more unused imports 2026-03-27 14:24:17 +09:00
Karl Seguin
0065677273 Merge pull request #2011 from lightpanda-io/mcp-fixes
MCP fixes
2026-03-27 13:02:59 +08:00
Karl Seguin
ea422075c7 Remove unused imports
And some smaller cleanups.
2026-03-27 12:45:26 +08:00
Adrià Arrufat
1d54e6944b mcp: send error response when message is too long 2026-03-27 11:36:18 +09:00
Adrià Arrufat
de32e5cf34 mcp: handle missing request IDs safely 2026-03-27 11:34:06 +09:00
Adrià Arrufat
c8d8ca5e94 mcp: improve error handling in resources and tools
- Handle failures during HTML, Markdown, and link serialization.
- Return MCP internal errors when result serialization fails.
- Refactor resource reading logic for better clarity and consistency.
2026-03-27 11:28:47 +09:00
Adrià Arrufat
da0828620f mcp: improve argument parsing error handling
Closes #1960
2026-03-27 10:04:45 +09:00
Adrià Arrufat
cdd33621e3 Merge pull request #2005 from lightpanda-io/mcp-lp-node-registry
MCP/CDP: unify node registration
2026-03-27 09:36:08 +09:00
Adrià Arrufat
7e778a17d6 MCP/CDP: unify node registration
This fixes a bug in MCP where interactive elements were not assigned
a backendNodeId, preventing agents from clicking or filling them. Also
extracts link collection to a shared browser module.
2026-03-26 23:51:43 +09:00
Adrià Arrufat
14fa2da2ad mcp: remove duplicate code in testLoadPage 2026-03-26 19:57:14 +09:00
Adrià Arrufat
96d24b5dc6 mcp: extract parseOptionalAndGetPage helper
Deduplicate the repeated "parse optional URL, maybe navigate, get page"
pattern across 6 MCP tool handlers (markdown, links, semantic_tree,
interactiveElements, structuredData, detectForms).
2026-03-26 19:44:44 +09:00
Adrià Arrufat
8e315e551a forms: extract form node registration logic 2026-03-25 09:30:06 +09:00
Adrià Arrufat
260768463b Merge branch 'main' into osc/feat-mcp-detect-forms 2026-03-24 09:25:47 +09:00
Karl Seguin
0fcdc1d194 Improve MCP tools test
Add helper to navigate to page, to reduce the boilerplate in each test.

Reduce waitForSelector time from 200ms to 20ms to speed up tests.
2026-03-23 19:15:50 +08:00
Matt Van Horn
35551ac84e fix: add disabled flag, external form fields, and param ordering
Address review feedback from @karlseguin:

1. Use Form.getElements() instead of manual TreeWalker for field
   collection. This reuses NodeLive(.form) which handles fields
   outside the <form> via the form="id" attribute per spec.

2. Add disabled detection: checks both the element's disabled
   attribute and ancestor <fieldset disabled> (with first-legend
   exemption per spec). Fields are flagged rather than excluded -
   agents need visibility into disabled state.

3. allocator is now the first parameter in collectForms/helpers.

4. handleDetectForms returns InvalidParams on bad input instead
   of silently swallowing parse errors.

5. Added tests for disabled fields, disabled fieldsets, and
   external form fields via form="id".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 23:31:59 -07:00
Adrià Arrufat
c3a2318eca fix: pass allocator as first parameter in forms.zig 2026-03-23 15:27:49 +09:00
Karl Seguin
c9bc370d6a Extract Session.wait into a Runner
This is done for a couple reasons. The first is just to have things a little
more self-contained for eventually supporting more advanced "wait" logic, e.g.
waiting for a selector.

The other is to provide callers with more fine-grained controlled. Specifically
the ability to manually "tick", so that they can [presumably] do something
after every tick. This is needed by the test runner to support more advanced
cases (cases that need to test beyond 'load') and it also improves (and fixes
potential use-after-free, the lp.waitForSelector)
2026-03-23 12:30:41 +08:00
Adrià Arrufat
4b29823a5b refactor: simplify form extraction and remove const casts 2026-03-23 13:24:21 +09:00
Karl Seguin
a69a22ccd7 Merge pull request #1948 from lightpanda-io/cdp-waitforselector
CDP: add waitForSelector to lp.actions
2026-03-23 10:09:09 +08:00
Adrià Arrufat
a6d2ec7610 refactor: share form node ID serialization between MCP and CDP 2026-03-23 10:18:24 +09:00
Adrià Arrufat
9e7f0b4776 test: verify feedback message content in click/fill/scroll MCP tools 2026-03-22 20:39:20 +09:00
Matt Van Horn
78c6def2b1 mcp: add detectForms tool for structured form discovery
Add a detectForms MCP tool and lp.detectForms CDP command that return
structured form metadata from the current page. Each form includes its
action URL, HTTP method, and fields with names, types, required status,
values, select options, and backendNodeIds for use with the fill tool.

This lets AI agents discover and fill forms in a single step instead of
calling interactiveElements, filtering for form fields, and guessing
which fields belong to which form.

New files:
- src/browser/forms.zig: FormInfo/FormField structs, collectForms()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:40:50 -07:00
Matt Van Horn
87a0690776 mcp: return page state from click/fill/scroll tools
After click, fill, and scroll actions, return the current page URL
and title instead of static success messages. This gives AI agents
immediate feedback about the page state after an action, matching
the pattern already used by waitForSelector.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 08:32:32 -07:00
Adrià Arrufat
e10ccd846d CDP: add waitForSelector to lp.actions
It refactors the implementation from MCP to be reused.
2026-03-22 00:09:02 +09:00
Matt Van Horn
e9bed18cd8 test: add waitForSelector MCP tool tests
Add three test cases covering:
- Immediate match on an already-present element
- Polling match on an element added after a 200ms setTimeout delay
- Timeout error on a non-existent element with a short timeout

Add mcp_wait_for_selector.html test fixture that injects a #delayed
element after 200ms via setTimeout for the polling test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 06:40:43 -07:00
Matt Van Horn
6008187c78 Add waitForSelector MCP tool
Adds a waitForSelector tool to the MCP server that polls for a CSS
selector match with a configurable timeout (default 5000ms). Returns the
backendNodeId of the matched element for use with click/fill tools.

The tool runs the session event loop between selector checks, so
dynamically-created elements are found as they appear from JS execution
or network responses.
2026-03-20 21:38:11 -07:00