Commit Graph
4 Commits
Author SHA1 Message Date
Ryan Vogel a73b58c031 feat(browser-extension): drive pages with Patchright so they can't detect the debugger
Bot checks (deviceandbrowserinfo.com's isAutomatedWithCDP and its worker
variant) override Error.prepareStackTrace and console.log an Error: with
CDP's Runtime domain enabled, Chrome serializes console arguments for the
debugger and calls the override. Playwright enables Runtime on every page and
worker. Patchright (patchright-core, a Playwright fork pinned to the same
1.63.0) never does.

- playwright-core is replaced by patchright-core (same API; two runtime
  imports, the rest types).
- Without Runtime, a page's console messages and uncaught errors don't reach
  execute. pageConsole.start()/stop() (new page-console.ts) enables Runtime
  on that one page through its own CDP session, drops what Chrome replays
  from before, and feeds the same execute logs. Documented in the skill and
  the MCP execute description.
- patchright-tuning.ts: Patchright finds elements by walking the DOM over CDP
  (for closed shadow roots), and pulled the whole DOM tree before every
  count()/evaluateAll()/all(). Through the extension, getByRole("link").count()
  on a 4,000-element Wikipedia page took ~650-1,900 ms vs Playwright's ~9-29
  ms. count() and querySelectorAll() go back to Playwright's lookup (injected
  script in the isolated world, which pages can't see) and the shadow-root
  scan is off; Playwright never reached into closed shadow roots either. The
  internals are reached through the first page's main frame; if an update
  renames them, lookups stay correct but slower and relay.log records
  patchright.tuning.

Verified in the user's Helium:
- deviceandbrowserinfo.com: isAutomatedWithCDP and isAutomatedWithCDPInWebWorker
  gone; only hasInconsistentWorkerValues remains (Helium reports
  hardwareConcurrency 16 on pages, 18 in workers; neither engine touches it).
  Sannysoft 31/31, BrowserScan 18/18 normal, reCAPTCHA v3 0.9, CreepJS 0%
  headless/stealth, Fingerprint scraping demo not blocked: unchanged.
- Upstream test suite: 880/888, the same 8 intentional failures as before.
- Benchmark page (form, iframe, 200-item list, snapshot, screenshot), 3 runs
  each: medians within noise, identical form results and snapshot hashes.
- Wikipedia: count/all/evaluateAll/textContent/isVisible within a few ms of
  Playwright with the same values; click, hover, fill, waitForSelector same.
- pageConsole: off by default (no page logs, page can't detect a debugger);
  start() captures log/warn/error/pageerror across executes and reloads;
  stop() makes the page undetectable again.
- Mouse/typing/scroll humanization unchanged.
2026-10-06 12:14:58 -04:00
Ryan Vogel 476f398510 feat(browser-extension): bring Browser Control into OpenCode Browser
OpenCode Browser no longer depends on the separate Browser Control product.
Its relay, CLI, MCP server, and agent guide (anomalyco/browser-control
8c80ac2, MIT, Anomaly) now live in packages/browser-extension/cli and ship
as the opencode-browser-cli npm package:

- Renamed throughout: `opencode-browser` command and MCP server,
  OPENCODE_BROWSER_* environment, opencode-browser skill, injected page ids.
- Its own port, 19988, so a Browser Control relay on 19989 can't hold it,
  and it accepts only OpenCode Browser's store and unpacked extension IDs
  (the path-hashed bundled-extension origin is gone).
- All files under one data root (src/paths.ts: ~/.local/share/
  opencode-browser, %LOCALAPPDATA% on Windows, OPENCODE_BROWSER_HOME):
  runtime, logs, relay catalogs and lifecycle, sessions, secrets.
- One entry (src/main.ts, bundled to dist/cli.mjs with npm dependencies
  external): setup commands (install, extension, uninstall, host) go to
  setup.ts, everything else to the relay CLI; `status` prints setup state
  first. The managed relay respawns the same entry.
- install now installs this exact version into <data root>/runtime with
  npm (OPENCODE_BROWSER_PACKAGE overrides the spec), points the native host
  and a new "opencode-browser" MCP entry at it, and warns about leftover
  browser-control MCP entries instead of configuring them. uninstall also
  removes the MCP entry and the data root.
- Logging: relay.log is always on (relay ready, extension connected/
  rejected/closed with codes, every HTTP request with status and ms except
  status/version polls, faults) and rotates to relay.log.1 instead of
  truncating; host.log records each native messaging request with timing.
- cli/ has its own package.json, bun.lock, and tsconfig so its pinned
  dependencies (effect 4.0.1, playwright-core 1.63.0, ...) stay out of the
  monorepo lockfile. The release workflow installs, typechecks, builds, and
  smoke tests it.

Verified: cli typecheck; browser-control's own test suite run against the
port outside the repo: 880/888 pass, the 8 failures assert the removed
layout (dist/mcp.js, path-hashed origins, extension/dist). From an npm pack
tarball in a temp HOME: install (5.7s), the native host answered service and
plugin requests, the MCP server listed 25 tools over stdio, and `execute`
started a managed relay, drove headless Chrome with the extension to
example.com, and returned the title; status and relay.log looked right.
2026-10-06 10:18:42 -04:00
Ryan Vogel 8ee61be65b ci: release OpenCode Browser with publish-browser-extension
cli/package.json is now the one release version: the store zip and the
extension bundled in the npm helper are stamped with it. Bumped to 0.0.2
(0.0.1 is on npm and in the store draft).

.github/workflows/publish-browser-extension.yml runs on a
browser-extension-v<version> tag (checked against cli/package.json) or by
hand: typecheck, build the helper and the store zip, smoke test the helper,
upload the zip as an artifact, then publish opencode-browser-cli to npm with
provenance (trusted publishing, or OPENCODE_BROWSER_NPM_TOKEN; skipped when the
version exists) and attach the zip to a GitHub release. Manual runs only
build unless `publish` is checked.

Verified: actionlint (only the repo's custom runner label is unknown to it);
locally, cli build + `bun run package` produced version 0.0.2 in both the zip
(no key) and the bundled extension, the built helper ran, and `npm pack
--dry-run` packs 0.0.2.
2026-10-03 19:25:25 -04:00
Ryan Vogel 6e6fadae5e feat(browser-extension): add opencode-browser-cli npm helper
`opencode browser install` only exists on this branch, so nobody on a
released opencode can connect the extension. packages/browser-extension/cli
is a standalone npm package (opencode-browser-cli) that does the same setup
without changing opencode:

- install: copies itself to ~/.local/share/opencode-browser (npx caches can
  be cleared), registers the ai.opencode.browser host for every installed
  Chromium browser (macOS/Linux manifests, Windows registry), adds the
  Browser Control MCP to opencode's global config (jsonc edits keep comments),
  starts the service, and copies the bundled unpacked extension to a
  permanent folder for Load unpacked.
- host: answers the extension with the URL and password from the user's
  installed `opencode service start` / `service get password`, and installs
  the extension's plugin.
- status, extension (opens the folder), uninstall.

The bundle includes jsonc-parser and the extension build (manifest key kept
so the unpacked ID matches the helper). The panel, welcome tab, store copy,
and privacy policy now point at `npx opencode-browser-cli install`. The
opencode CLI command is unchanged.

Verified: lint, extension typecheck; `npm pack` then npx from the tarball in
a temp HOME/XDG registered Helium, kept a commented opencode.json and added
the MCP entry, started the service; the wrapper answered service (URL +
password) and plugin (written) messages over native messaging; status and
uninstall worked.
2026-10-02 20:38:40 -04:00