Repository navigation
feat: add browser automation tool and default file tool path - #1530
Merged
Merged
Conversation
OpenSpec change for a browser-automation tool that drives a headless Chromium browser via puppeteer-core, supporting navigate, click, type/fill, press, screenshot, extract, waitFor, and evaluate actions with URL validation against the sandbox allowlist.
Add a browser tool that drives a real headless Chromium via puppeteer-core: navigate, click, type, fill, press, screenshot, extract, waitFor, evaluate, and close. Supports persistent sessions via sessionId for chaining actions across calls. Validates outbound URLs against the sandbox allowlist (SSRF protection). Includes unit tests for the Zod schema and action dispatch.
Replace new Function() wrapping with a direct string expression passed to page.evaluate. Puppeteer evaluates string arguments as Runtime.evaluate expressions, so no function-body wrapping is needed. Removes the AGENTS.md forbidden-pattern violation (new Function) and updates the schema description and tests to use expression strings.
networkidle0/networkidle2 block on pages with persistent connections (ads, trackers, streaming) and false-timeout. The load event fires when the page's resources are done loading without waiting for network idle.
The browser tool's screenshot action now captures a JPEG via puppeteer,
writes it to memory/screenshots/, and returns { ok, mimeType: "image/jpeg",
path } so the agent can feed the path to readImage for vision analysis.
This is a 1:1 match with the removed screenshotWeb tool. The screenshots
directory is injectable via options for tests.
Make the file tool's path argument optional, defaulting it to the active project cwd (falling back to config.cwd) and resolving relative paths against that base — mirroring the @ file picker. Adds a module-level active-project store that the TUI writes to on select/clear and the file tool reads at call time.
Every browser call now persists its session and returns the sessionId in the response, so callers can chain actions (navigate -> extract -> close) without supplying a sessionId up front. Unused sessions are reclaimed by the existing 5-minute idle GC. Also align the file tool's glob action with search/grep by reading the shared `pattern` parameter instead of a separate `glob` key.
The sandbox allowlist contained a relative "./" entry, which resolves against process.cwd() and drifts when the process changes directory. This caused scanAgents and other path-validating tools to reject paths that were actually inside the project. Normalize sandbox.paths in _setResolvedConfig: drop relative "."/"./" entries and append the absolute config.cwd, so every consumer (path validation, tool allowlists, subagent scopes) sees the project root explicitly regardless of the process working directory.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a
browserautomation tool that drives a real headless Chromium browser viapuppeteer-core, supportingnavigate,click,type/fill,press,screenshot,extract,waitFor, andevaluateactions. Every outbound URL is validated againstfilterUrl(SSRF protection). This closes the gap between madz's read-only web toolset and actually acting on a web page, and replaces the deprecatedextractWeb/renderWeb/screenshotWebtools.Also makes the
filetool'spathargument optional, defaulting it to the active project cwd (falling back toconfig.cwd) and resolving relative paths against that base — mirroring the@file picker. Adds a module-level active-project store (src/workspace/project.js) that the TUI writes to on select/clear and the file tool reads at call time. Normalizes the sandbox allowlist so relative"./"entries are replaced with the absoluteconfig.cwd.Type of Change
Testing
tests/unit/tools/browser.test.js— Zod schema validation for all actions and inputs, URL rejection viafilterUrl, session reuse/close.tests/unit/tools/file.test.js— default-path and relative-path resolution against the active project cwd.tests/unit/workspace/project.test.js— active-project store get/set/clear.tests/unit/config_loader.test.js— sandbox path normalization.openspec/changes/browser-automation-tool/tasks.md.Coverage
Checklist
npm run lintpassesCloses #1517