@intentic/browser 1.310.0 → 1.312.0

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.
Files changed (2) hide show
  1. package/README.md +24 -81
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,88 +1,31 @@
1
- # @intentic/browser
1
+ # browser
2
2
 
3
- Drive a Chromium-family browser from Node over CDP: open pages, read them as **structured text**, and click and
4
- type by element reference. No dependencies.
3
+ Drives a Chromium-family browser from Node over the DevTools protocol: opens pages, lists what can be clicked as numbered refs, and clicks and types by ref.
5
4
 
6
- ```ts
7
- import { browser } from "@intentic/browser";
8
-
9
- const web = browser();
10
- const page = await web.open("https://example.com/login");
11
- // page.elements → [{ ref: "e0", role: "textbox", name: "Email" }, …]
12
-
13
- await web.fill("e0", "someone@example.com");
14
- await web.fill("e1", "…", true); // true = submit
15
- const after = await web.snapshot();
5
+ ```mermaid
6
+ flowchart LR
7
+ tools["intentic-machine<br/>browser_* tools"] --> browser(["browser()"])
8
+ browser -->|"ensureBrowser"| binary["Brave, Chrome or Edge<br/>own profile, debugging port"]
9
+ browser -->|"CDP over WebSocket"| tab["The agent's tab"]
10
+ page["./page<br/>refs and rendering"] --> browser
11
+ page --> webext["webext<br/>same vocabulary"]
16
12
  ```
17
13
 
18
- ## Why references instead of coordinates
19
-
20
- A browser can be operated by clicking pixels, and it is miserable: the coordinates move when the window moves, a
21
- scroll invalidates every one of them, and "the Submit button" is a guess about which grey rectangle is which.
22
-
23
- A browser will simply tell you what it is showing. So this asks it: one snapshot returns every visible element
24
- with its role (`link`, `button`, `textbox`), its accessible name, and what it currently holds: and every action
25
- names an element rather than a position. The same instruction then works at any window size, on any machine,
26
- after any re-render.
27
-
28
- **Refs are deliberately short-lived.** They index an array parked on the page, and the next snapshot replaces it,
29
- so a ref taken before a click that navigated cannot silently address whatever now occupies that slot. A stale ref
30
- fails loudly, which is the behaviour worth having.
31
-
32
- ## Which browser it drives
33
-
34
- **Their browser, not their profile.** A browser only speaks CDP if it was started with `--remote-debugging-port`,
35
- and nobody's everyday browser was; restarting theirs to add the flag would close every tab they had open. So: if a
36
- debugging endpoint is already there, it is used; otherwise a separate instance starts with its own profile
37
- directory under `~/.intentic/browser`, one per browser: a user-data-dir records the build that wrote it, and
38
- Chromium refuses a profile from a newer version than its own, so Brave must not be handed the directory Edge left.
39
-
40
- That separate profile is a feature rather than a compromise. It is empty the first time, so the user signs into
41
- whatever is needed once, in a window they can watch, and it persists afterwards. Their own session is never
42
- automated and never at risk from a misfired click.
43
-
44
- Which *binary* gets started is asked of the OS, not guessed: the browser registered for `https` (Windows'
45
- `UserChoice` ProgId, `xdg-settings get default-web-browser` on Linux), used whenever it is Chromium-family. A
46
- default that cannot speak CDP — Firefox, Safari — falls through to the guesses in `browserCandidates`, and those
47
- are ordered so a browser installed on purpose outranks one the OS shipped: Brave, then Chrome, then Edge.
48
-
49
- With one exception, which was reported as a bug and is one: **Edge registered as the default does not count as a
50
- choice.** Windows ships Edge and hands it the `https` association, and setting a different default takes a
51
- deliberate trip through Settings that a fresh install does not always win — so on a machine whose owner lives in
52
- Brave, "the default browser" answers Edge, and an agent opening Edge in front of them is simply wrong. When the
53
- OS's answer is the browser it shipped and something else is installed, the installed one wins (`pickBrowser`).
54
- Nothing of the person's rides on either choice: the profile is this package's own, empty of their logins and
55
- extensions whichever binary starts.
56
-
57
- ## Why hand-rolled CDP rather than Puppeteer or Playwright
58
-
59
- **Not because Playwright is too heavy to ship.** It bundles into the `bun build --compile` binary this ends up
60
- inside perfectly well: one `--external chromium-bidi`, for a require its own bundle makes and never resolves, and
61
- about 6 MB on top of a binary that already weighs ~95 MB. Anyone who assumes packaging is the obstacle will try
62
- it, watch it compile, and conclude this package exists for no reason.
63
-
64
- **It is that Playwright cannot reach a browser from Bun.** `chromium.connectOverCDP()` fetches the debugger's
65
- WebSocket URL over HTTP, then stalls on the upgrade and times out thirty seconds later. That happens compiled and
66
- uncompiled alike, so it is the runtime rather than the bundling: and the same script against the same Chrome on
67
- Node drives the page and returns an accessibility snapshot. Bun's own global `WebSocket`, which is what this
68
- package is built on, connects from inside the compiled binary and gets a CDP reply back.
69
-
70
- CDP needs no dependency either way. The protocol is JSON, `fetch` and `WebSocket` are globals, and the ~200 lines
71
- here are the subset that driving a page actually uses.
72
-
73
- **Worth re-testing rather than inheriting.** The above was measured against playwright-core 1.62.1 on Bun 1.4.1.
74
- If a later pair connects, Playwright's accessibility snapshot is a better instrument than the DOM walk in
75
- `snapshot.ts`, and this whole package is ~500 lines: the trade would be worth making, not merely tolerable.
76
-
77
- ## What is testable without a browser
78
-
79
- `snapshot.ts`'s renderer and ref parsing, the per-platform candidate list, and the parsing of what the OS answers
80
- about its default browser (a registry open command, a `.desktop` Exec line): all pure. Asking the OS shells out,
81
- and the CDP calls end in a real browser painting a real page; those need a machine, not a test.
14
+ - Runs on the user's device inside [`intentic-machine`](../machine). It never touches the user's own profile:
15
+ `ensureBrowser` reuses whatever answers on `DEFAULT_PORT`, otherwise it starts the OS default Chromium-family
16
+ browser with `--remote-debugging-port` and a profile of its own under `~/.intentic/browser/<browser>`. Edge
17
+ ranks below any Chromium browser someone installed by choice (`pickBrowser`).
18
+ - A snapshot (`SNAPSHOT_SCRIPT`) lists visible interactive elements as refs `e0`, `e1`, … A ref lives until the next
19
+ snapshot, and a stale one fails with a message instead of clicking whatever sits there now.
20
+ - Clicks and fills run as DOM calls inside the page and fire `input` and `change`, so they survive scrolling and
21
+ reach a framework's state. Key presses go through `Input.dispatchKeyEvent`, since pages ignore synthetic keyboard events.
22
+ - The `./page` entry point has no DOM or Node imports, so the [browser extension](../webext) renders pages with
23
+ the same `renderPage`.
82
24
 
83
25
  ## Key files
84
26
 
85
- - [src/index.ts](src/index.ts): the public surface.
86
- - [src/cdp.ts](src/cdp.ts): the hand-rolled Chrome DevTools Protocol client.
87
- - [src/snapshot.ts](src/snapshot.ts): a page as structured text with stable element references.
88
- - [src/launch.ts](src/launch.ts): finding and starting a browser.
27
+ - [src/index.ts](src/index.ts) — `browser()`: one CDP session per object, and every page action.
28
+ - [src/launch.ts](src/launch.ts) — which binary to start, its flags and its profile directory.
29
+ - [src/snapshot.ts](src/snapshot.ts) — the in-page script that numbers the elements.
30
+ - [src/page.ts](src/page.ts) — `PageState`, `renderPage` and ref parsing, shared with the extension.
31
+ - [src/cdp.ts](src/cdp.ts) — the DevTools protocol subset: find tabs, attach, send.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/browser",
3
- "version": "1.310.0",
3
+ "version": "1.312.0",
4
4
  "description": "Drive a Chromium browser from Node over CDP — open pages, read them as structured text, click and type by element reference. No dependencies.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,14 +41,14 @@
41
41
  }
42
42
  },
43
43
  "dependencies": {
44
- "@intentic/base": "1.310.0",
44
+ "@intentic/base": "1.312.0",
45
45
  "tslib": "2.8.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@intentic/testing": "0.0.0",
49
49
  "@intentic/tsconfig": "0.0.0",
50
- "@types/bun": "1.4.0",
51
- "@types/node": "24.13.2",
50
+ "@types/bun": "1.4.2",
51
+ "@types/node": "24.13.6",
52
52
  "@typescript/native-preview": "7.0.0-dev.20260707.2"
53
53
  },
54
54
  "scripts": {