@orkestrel/browser 0.0.25 → 0.0.27

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.
package/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # @orkestrel/browser
2
2
 
3
- > A Chrome DevTools Protocol automation layer for Chromium-family browsers: an
4
- > environment-agnostic core that drives pages, elements, and readings over an injected transport
5
- > and publishes them as agent tools, an in-page face that drives a DOM document with native APIs,
6
- > and a Node runtime that finds, launches, and connects to the browser itself.
3
+ > The browser runtime for the `@orkestrel` line: a `Browser` that finds, launches, or attaches
4
+ > to Chromium; its contexts and pages; the elements and readings a page yields; and the toolset
5
+ > and journeys that hand a page to an agent.
7
6
 
8
- Connect to a running browser or launch one with the `createBrowser` function, open a page, and drive it through stable element references and trusted input. Read the whole captured page as Markdown or plain text in bounded slices, and hand the whole vocabulary to an agent as `@orkestrel/tool` tools with `createBrowserToolset`. Inside a page, `createDocumentToolset` drives a DOM document with native APIs, and `createSocketCDPTransport` carries the core client over the browser's own `WebSocket`. Record a journey, one user intent kept as JSON, from a model's tool calls or a person's gestures on a page, then list, edit, replay, and forget it through the six journey tools, or compile it with `compileBrowserJourney` into a module a developer runs and customizes. Part of the `@orkestrel` line.
7
+ Connect to a running browser or launch one with the `createBrowser` function, open a page, and drive it through stable element references and trusted input. Read the whole captured page as Markdown or plain text in bounded slices, and hand the whole vocabulary to an agent as `@orkestrel/tool` tools with `createBrowserToolset`. Inside a page, `createBrowserToolset(createBrowserDOMView(options))` drives a DOM document with native APIs, and `createSocketCDPTransport` carries the core client over the browser's own `WebSocket`. Record a journey, one user intent kept as JSON, from a model's tool calls or a person's gestures on a page, then list, edit, replay, and forget it through the seven journey tools, or compile it with `compileBrowserJourney` into a module a developer runs and customizes. Part of the `@orkestrel` line.
9
8
 
10
9
  ## Install
11
10
 
@@ -32,7 +31,12 @@ import { createBrowser } from '@orkestrel/browser/server'
32
31
 
33
32
  const browser = createBrowser({ headless: true })
34
33
  await browser.connect()
35
- const page = await browser.create({ url: 'https://example.com' })
34
+ const url =
35
+ 'data:text/html,' +
36
+ encodeURIComponent(
37
+ '<label>Email<input aria-label="Email"></label><button onclick="document.body.append(&quot;Saved&quot;)">Save</button>',
38
+ )
39
+ const page = await browser.create({ url })
36
40
  const outline = await page.elements.outline() // the page's text and elements, with references such as e4
37
41
  const [email] = await page.elements.find({ role: 'textbox', name: 'Email' })
38
42
  await email?.fill('sam@example.test')
@@ -54,9 +58,13 @@ import { createToolManager } from '@orkestrel/tool'
54
58
 
55
59
  const toolset = createBrowserToolset(page, { tools: createToolManager() })
56
60
  await toolset.start()
57
- await toolset.tools.execute({ id: '1', name: 'look', arguments: { search: 'Email' } })
58
- await toolset.tools.execute({ id: '2', name: 'read', arguments: { search: 'delivery' } })
59
- await toolset.tools.execute({ id: '3', name: 'plain', arguments: { search: 'confirmation' } })
61
+ await toolset.tools.execute({ id: '1', name: 'read', arguments: { from: 1, search: 'Email' } })
62
+ await toolset.tools.execute({ id: '2', name: 'read', arguments: { from: 1, search: 'delivery' } })
63
+ await toolset.tools.execute({
64
+ id: '3',
65
+ name: 'read',
66
+ arguments: { from: 1, search: 'confirmation' },
67
+ })
60
68
  await toolset.destroy()
61
69
  ```
62
70
 
@@ -71,9 +79,11 @@ const result = await client.send('Page.navigate', { url: 'https://example.com' }
71
79
  await client.close()
72
80
  ```
73
81
 
82
+ Context wrapping uses `BrowserContextOptions`; `browser.isolate` uses `BrowserIsolateOptions` and assigns the context id. The stable `page.recorder` reports `active` and starts explicitly. Network `apply` retains omitted or undefined settings; `clear()` resets headers, offline mode, and credentials. Cookie `remove` requires a nonempty filter; `clear()` removes all cookies.
83
+
74
84
  ## Browse binary
75
85
 
76
- The package ships the `browse` binary, which serves the browser vocabulary and the journey tools over MCP on stdio and starts Chromium when the server starts, before the client's first request, keeping journeys and runs under `tmp/browsers`. Register it for a checkout with `claude mcp add --scope project browse -- node node_modules/@orkestrel/browser/dist/bin/main.js`, which writes the `browse` entry of the project's `.mcp.json`, then start `claude` in the checkout and approve the server; `BROWSE_ROOT`, `BROWSE_HEADLESS`, `BROWSE_EXECUTABLE`, `BROWSE_READONLY`, and `BROWSE_POOL` configure it. See [Register the browse binary with Claude Code](guides/browser.md#register-the-browse-binary-with-claude-code) for the entry, the approval, the startup and recovery behavior, and a recorded exchange.
86
+ The package ships the `browse` binary, which serves the browser vocabulary and the journey tools over MCP on stdio and starts Chromium when the server starts, before the client's first request, keeping journeys and runs under `tmp/browsers`. Register it for a checkout with `claude mcp add --scope project browse -- node node_modules/@orkestrel/browser/dist/bin/main.js`, which writes the `browse` entry of the project's `.mcp.json`, then start `claude` in the checkout and approve the server; `BROWSE_ROOT`, `BROWSE_HEADLESS`, `BROWSE_EXECUTABLE`, `BROWSE_READONLY`, and `BROWSE_POOL` configure it. See [Register the browse binary with Claude Code](guides/browser.md#register-the-browse-binary-with-claude-code) for the entry, the approval, the startup and recovery behavior, and an illustrative exchange.
77
87
 
78
88
  ## Guide
79
89
 
@@ -83,9 +93,9 @@ For the full surface of the three faces, the method tables, the toolset vocabula
83
93
 
84
94
  The `exports` field in `package.json` names three entry points:
85
95
 
86
- - `.`, the environment-agnostic core: `CDPClient`, `BrowserContext`, `BrowserPage`, `BrowserFrame`, `BrowserNavigationManager`, the element managers, `BrowserPageElement`, `BrowserReading`, `BrowserToolset`, `BrowserSnapshot`, `BrowserCodegen`, `BrowserRecorder`, `BrowserReplay`, `BrowserJourneyToolset`, the memory journey and run stores, `compileBrowserJourney`, and the factories `createCDPClient`, `createBrowserReading`, `createBrowserSnapshot`, `createBrowserToolset`, `createBrowserRecorder`, `createBrowserReplay`, `createMemoryBrowserJourneyStore`, and `createMemoryBrowserRunStore`;
87
- - `./browser`, the in-page face: `BrowserDOMView`, `BrowserDOMElement`, `BrowserDOMElementManager`, `SocketCDPTransport`, and the factories `createBrowserDOMView`, `createDocumentToolset`, and `createSocketCDPTransport`;
88
- - `./server`, the Node runtime: `Browser`, `WebSocketCDPTransport`, `FileBrowserWriter`, the file journey and run stores, `BrowserMCPServer`, and the factories `createBrowser`, `createCDPTransport`, `createBrowserWriter`, `createFileBrowserJourneyStore`, `createFileBrowserRunStore`, and `createBrowserMCPServer`.
96
+ - `.`, the core: context and page contracts, elements and readings, the toolset, recorder, replay, memory stores, journey compiler, and their factories. Owners construct pages, frames, elements, input devices, and managers and return their public interfaces; `createBrowserContext` constructs a context over an injected CDP client.
97
+ - `./browser`, the in-page face: `BrowserDOMView`, `BrowserDOMWait`, `SocketCDPTransport`, `createBrowserDOMView`, and `createSocketCDPTransport`. Compose the view with the core's `createBrowserToolset`.
98
+ - `./server`, the Node runtime: `Browser`, `WebSocketCDPTransport`, `FileBrowserWriter`, the file journey and run stores, `BrowserMCPServer`, and the factories `createBrowser`, `createWebSocketCDPTransport`, `createFileBrowserWriter`, `createFileBrowserJourneyStore`, `createFileBrowserRunStore`, and `createBrowserMCPServer`.
89
99
 
90
100
  The `bin` field names `browse`, which runs `dist/bin/main.js`.
91
101
 
package/dist/bin/main.js CHANGED
@@ -21,32 +21,34 @@ try {
21
21
  "BROWSE_READONLY",
22
22
  BROWSE_READONLY,
23
23
  readonly
24
- ]]) if (value !== void 0 && value !== "" && parsed === void 0) throw new BrowserError(`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`, "BROWSER_SERVER_ENVIRONMENT", {
24
+ ]]) if (value !== void 0 && value !== "" && parsed === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`, {
25
25
  name,
26
26
  value
27
27
  });
28
- if (BROWSE_POOL !== void 0 && BROWSE_POOL !== "" && size === void 0) throw new BrowserError(`BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`, "BROWSER_SERVER_ENVIRONMENT", {
28
+ if (BROWSE_POOL !== void 0 && BROWSE_POOL !== "" && size === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`, {
29
29
  name: "BROWSE_POOL",
30
30
  value: BROWSE_POOL
31
31
  });
32
- if (BROWSE_VIEWPORT !== void 0 && BROWSE_VIEWPORT !== "" && viewport === void 0) throw new BrowserError(`BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`, "BROWSER_SERVER_ENVIRONMENT", {
32
+ if (BROWSE_VIEWPORT !== void 0 && BROWSE_VIEWPORT !== "" && viewport === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`, {
33
33
  name: "BROWSE_VIEWPORT",
34
34
  value: BROWSE_VIEWPORT
35
35
  });
36
- if (BROWSE_CONTEXTS !== void 0 && BROWSE_CONTEXTS !== "" && contexts === void 0) throw new BrowserError(`BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`, "BROWSER_SERVER_ENVIRONMENT", {
36
+ if (BROWSE_CONTEXTS !== void 0 && BROWSE_CONTEXTS !== "" && contexts === void 0) throw new BrowserError("SERVER_ENVIRONMENT", `BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`, {
37
37
  name: "BROWSE_CONTEXTS",
38
38
  value: BROWSE_CONTEXTS
39
39
  });
40
40
  await createBrowserMCPServer({
41
41
  ...BROWSE_ROOT === void 0 || BROWSE_ROOT === "" ? {} : { root: BROWSE_ROOT },
42
- ...headless === void 0 ? {} : { headless },
43
- ...BROWSE_EXECUTABLE === void 0 || BROWSE_EXECUTABLE === "" ? {} : { executable: BROWSE_EXECUTABLE },
44
- ...readonly === void 0 ? {} : { readonly },
42
+ browser: {
43
+ ...headless === void 0 ? {} : { headless },
44
+ ...BROWSE_EXECUTABLE === void 0 || BROWSE_EXECUTABLE === "" ? {} : { executable: BROWSE_EXECUTABLE },
45
+ ...viewport === void 0 ? {} : { viewport }
46
+ },
47
+ journeys: { ...readonly === void 0 ? {} : { readonly } },
45
48
  pool: {
46
49
  ...size === void 0 ? {} : { size },
47
50
  ...contexts === void 0 ? {} : { contexts }
48
- },
49
- ...viewport === void 0 ? {} : { viewport }
51
+ }
50
52
  }).start();
51
53
  } catch (error) {
52
54
  if (!isBrowserError(error)) throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":[],"sources":["../../src/bin/main.ts"],"sourcesContent":["import { parseBoolean, parseInteger } from '@orkestrel/contract'\nimport { BrowserError, isBrowserError } from '@src/core'\nimport { createBrowserMCPServer, parseBrowserViewport } from '@src/server'\n\n// The entry owns stderr; a closed reader must not interrupt the server's teardown barrier.\nprocess.stderr.on('error', () => {\n\tprocess.exitCode = 1\n})\n\ntry {\n\tconst {\n\t\tBROWSE_ROOT,\n\t\tBROWSE_HEADLESS,\n\t\tBROWSE_EXECUTABLE,\n\t\tBROWSE_READONLY,\n\t\tBROWSE_POOL,\n\t\tBROWSE_CONTEXTS,\n\t\tBROWSE_VIEWPORT,\n\t} = process.env\n\tconst headless = parseBoolean(BROWSE_HEADLESS)\n\tconst readonly = parseBoolean(BROWSE_READONLY)\n\tconst size = parseInteger(BROWSE_POOL)\n\tconst contexts = parseInteger(BROWSE_CONTEXTS)\n\tconst viewport = parseBrowserViewport(BROWSE_VIEWPORT)\n\t// An empty variable counts as unset, as a shell's `NAME=` leaves it.\n\tfor (const [name, value, parsed] of [\n\t\t['BROWSE_HEADLESS', BROWSE_HEADLESS, headless],\n\t\t['BROWSE_READONLY', BROWSE_READONLY, readonly],\n\t] as const) {\n\t\tif (value !== undefined && value !== '' && parsed === undefined) {\n\t\t\tthrow new BrowserError(\n\t\t\t\t`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`,\n\t\t\t\t'BROWSER_SERVER_ENVIRONMENT',\n\t\t\t\t{ name, value },\n\t\t\t)\n\t\t}\n\t}\n\tif (BROWSE_POOL !== undefined && BROWSE_POOL !== '' && size === undefined)\n\t\tthrow new BrowserError(\n\t\t\t`BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`,\n\t\t\t'BROWSER_SERVER_ENVIRONMENT',\n\t\t\t{ name: 'BROWSE_POOL', value: BROWSE_POOL },\n\t\t)\n\tif (BROWSE_VIEWPORT !== undefined && BROWSE_VIEWPORT !== '' && viewport === undefined)\n\t\tthrow new BrowserError(\n\t\t\t`BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`,\n\t\t\t'BROWSER_SERVER_ENVIRONMENT',\n\t\t\t{ name: 'BROWSE_VIEWPORT', value: BROWSE_VIEWPORT },\n\t\t)\n\tif (BROWSE_CONTEXTS !== undefined && BROWSE_CONTEXTS !== '' && contexts === undefined)\n\t\tthrow new BrowserError(\n\t\t\t`BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`,\n\t\t\t'BROWSER_SERVER_ENVIRONMENT',\n\t\t\t{ name: 'BROWSE_CONTEXTS', value: BROWSE_CONTEXTS },\n\t\t)\n\tawait createBrowserMCPServer({\n\t\t...(BROWSE_ROOT === undefined || BROWSE_ROOT === '' ? {} : { root: BROWSE_ROOT }),\n\t\t...(headless === undefined ? {} : { headless }),\n\t\t...(BROWSE_EXECUTABLE === undefined || BROWSE_EXECUTABLE === ''\n\t\t\t? {}\n\t\t\t: { executable: BROWSE_EXECUTABLE }),\n\t\t...(readonly === undefined ? {} : { readonly }),\n\t\tpool: {\n\t\t\t...(size === undefined ? {} : { size }),\n\t\t\t...(contexts === undefined ? {} : { contexts }),\n\t\t},\n\t\t...(viewport === undefined ? {} : { viewport }),\n\t}).start()\n} catch (error) {\n\tif (!isBrowserError(error)) throw error\n\tconsole.error(`browse: ${error.code}: ${error.message.split(/\\r\\n|\\n/u).join(' ')}`)\n\tprocess.exitCode = 1\n}\n"],"mappings":";;;;;AAKA,QAAQ,OAAO,GAAG,eAAe;CAChC,QAAQ,WAAW;AACpB,CAAC;AAED,IAAI;CACH,MAAM,EACL,aACA,iBACA,mBACA,iBACA,aACA,iBACA,oBACG,QAAQ;CACZ,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,OAAO,aAAa,WAAW;CACrC,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,qBAAqB,eAAe;CAErD,KAAK,MAAM,CAAC,MAAM,OAAO,WAAW,CACnC;EAAC;EAAmB;EAAiB;CAAQ,GAC7C;EAAC;EAAmB;EAAiB;CAAQ,CAC9C,GACC,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,WAAW,KAAA,GACrD,MAAM,IAAI,aACT,GAAG,KAAK,qCAAqC,KAAK,UAAU,KAAK,KACjE,8BACA;EAAE;EAAM;CAAM,CACf;CAGF,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,MAAM,SAAS,KAAA,GAC/D,MAAM,IAAI,aACT,uCAAuC,KAAK,UAAU,WAAW,KACjE,8BACA;EAAE,MAAM;EAAe,OAAO;CAAY,CAC3C;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,uEAAuE,KAAK,UAAU,eAAe,KACrG,8BACA;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,2CAA2C,KAAK,UAAU,eAAe,KACzE,8BACA;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,MAAM,uBAAuB;EAC5B,GAAI,gBAAgB,KAAA,KAAa,gBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,YAAY;EAC/E,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC7C,GAAI,sBAAsB,KAAA,KAAa,sBAAsB,KAC1D,CAAC,IACD,EAAE,YAAY,kBAAkB;EACnC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC7C,MAAM;GACL,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;GACrC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC9C;EACA,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;CAC9C,CAAC,CAAC,CAAC,MAAM;AACV,SAAS,OAAO;CACf,IAAI,CAAC,eAAe,KAAK,GAAG,MAAM;CAClC,QAAQ,MAAM,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,MAAM,UAAU,CAAC,CAAC,KAAK,GAAG,GAAG;CACnF,QAAQ,WAAW;AACpB"}
1
+ {"version":3,"file":"main.js","names":[],"sources":["../../src/bin/main.ts"],"sourcesContent":["import { parseBoolean, parseInteger } from '@orkestrel/contract'\nimport { BrowserError, isBrowserError } from '@src/core'\nimport { createBrowserMCPServer, parseBrowserViewport } from '@src/server'\n\n// The entry owns stderr; a closed reader must not interrupt the server's teardown barrier.\nprocess.stderr.on('error', () => {\n\tprocess.exitCode = 1\n})\n\ntry {\n\tconst {\n\t\tBROWSE_ROOT,\n\t\tBROWSE_HEADLESS,\n\t\tBROWSE_EXECUTABLE,\n\t\tBROWSE_READONLY,\n\t\tBROWSE_POOL,\n\t\tBROWSE_CONTEXTS,\n\t\tBROWSE_VIEWPORT,\n\t} = process.env\n\tconst headless = parseBoolean(BROWSE_HEADLESS)\n\tconst readonly = parseBoolean(BROWSE_READONLY)\n\tconst size = parseInteger(BROWSE_POOL)\n\tconst contexts = parseInteger(BROWSE_CONTEXTS)\n\tconst viewport = parseBrowserViewport(BROWSE_VIEWPORT)\n\t// An empty variable counts as unset, as a shell's `NAME=` leaves it.\n\tfor (const [name, value, parsed] of [\n\t\t['BROWSE_HEADLESS', BROWSE_HEADLESS, headless],\n\t\t['BROWSE_READONLY', BROWSE_READONLY, readonly],\n\t] as const) {\n\t\tif (value !== undefined && value !== '' && parsed === undefined) {\n\t\t\tthrow new BrowserError(\n\t\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t\t`${name} must be true, false, 1, or 0, not ${JSON.stringify(value)}`,\n\t\t\t\t{ name, value },\n\t\t\t)\n\t\t}\n\t}\n\tif (BROWSE_POOL !== undefined && BROWSE_POOL !== '' && size === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_POOL must be an integer, not ${JSON.stringify(BROWSE_POOL)}`,\n\t\t\t{ name: 'BROWSE_POOL', value: BROWSE_POOL },\n\t\t)\n\tif (BROWSE_VIEWPORT !== undefined && BROWSE_VIEWPORT !== '' && viewport === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_VIEWPORT must be positive integers in WIDTHxHEIGHT form, not ${JSON.stringify(BROWSE_VIEWPORT)}`,\n\t\t\t{ name: 'BROWSE_VIEWPORT', value: BROWSE_VIEWPORT },\n\t\t)\n\tif (BROWSE_CONTEXTS !== undefined && BROWSE_CONTEXTS !== '' && contexts === undefined)\n\t\tthrow new BrowserError(\n\t\t\t'SERVER_ENVIRONMENT',\n\t\t\t`BROWSE_CONTEXTS must be an integer, not ${JSON.stringify(BROWSE_CONTEXTS)}`,\n\t\t\t{ name: 'BROWSE_CONTEXTS', value: BROWSE_CONTEXTS },\n\t\t)\n\tawait createBrowserMCPServer({\n\t\t...(BROWSE_ROOT === undefined || BROWSE_ROOT === '' ? {} : { root: BROWSE_ROOT }),\n\t\tbrowser: {\n\t\t\t...(headless === undefined ? {} : { headless }),\n\t\t\t...(BROWSE_EXECUTABLE === undefined || BROWSE_EXECUTABLE === ''\n\t\t\t\t? {}\n\t\t\t\t: { executable: BROWSE_EXECUTABLE }),\n\t\t\t...(viewport === undefined ? {} : { viewport }),\n\t\t},\n\t\tjourneys: { ...(readonly === undefined ? {} : { readonly }) },\n\t\tpool: {\n\t\t\t...(size === undefined ? {} : { size }),\n\t\t\t...(contexts === undefined ? {} : { contexts }),\n\t\t},\n\t}).start()\n} catch (error) {\n\tif (!isBrowserError(error)) throw error\n\tconsole.error(`browse: ${error.code}: ${error.message.split(/\\r\\n|\\n/u).join(' ')}`)\n\tprocess.exitCode = 1\n}\n"],"mappings":";;;;;AAKA,QAAQ,OAAO,GAAG,eAAe;CAChC,QAAQ,WAAW;AACpB,CAAC;AAED,IAAI;CACH,MAAM,EACL,aACA,iBACA,mBACA,iBACA,aACA,iBACA,oBACG,QAAQ;CACZ,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,OAAO,aAAa,WAAW;CACrC,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,WAAW,qBAAqB,eAAe;CAErD,KAAK,MAAM,CAAC,MAAM,OAAO,WAAW,CACnC;EAAC;EAAmB;EAAiB;CAAQ,GAC7C;EAAC;EAAmB;EAAiB;CAAQ,CAC9C,GACC,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,WAAW,KAAA,GACrD,MAAM,IAAI,aACT,sBACA,GAAG,KAAK,qCAAqC,KAAK,UAAU,KAAK,KACjE;EAAE;EAAM;CAAM,CACf;CAGF,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,MAAM,SAAS,KAAA,GAC/D,MAAM,IAAI,aACT,sBACA,uCAAuC,KAAK,UAAU,WAAW,KACjE;EAAE,MAAM;EAAe,OAAO;CAAY,CAC3C;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,sBACA,uEAAuE,KAAK,UAAU,eAAe,KACrG;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,IAAI,oBAAoB,KAAA,KAAa,oBAAoB,MAAM,aAAa,KAAA,GAC3E,MAAM,IAAI,aACT,sBACA,2CAA2C,KAAK,UAAU,eAAe,KACzE;EAAE,MAAM;EAAmB,OAAO;CAAgB,CACnD;CACD,MAAM,uBAAuB;EAC5B,GAAI,gBAAgB,KAAA,KAAa,gBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,YAAY;EAC/E,SAAS;GACR,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;GAC7C,GAAI,sBAAsB,KAAA,KAAa,sBAAsB,KAC1D,CAAC,IACD,EAAE,YAAY,kBAAkB;GACnC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC9C;EACA,UAAU,EAAE,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,EAAG;EAC5D,MAAM;GACL,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;GACrC,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC9C;CACD,CAAC,CAAC,CAAC,MAAM;AACV,SAAS,OAAO;CACf,IAAI,CAAC,eAAe,KAAK,GAAG,MAAM;CAClC,QAAQ,MAAM,WAAW,MAAM,KAAK,IAAI,MAAM,QAAQ,MAAM,UAAU,CAAC,CAAC,KAAK,GAAG,GAAG;CACnF,QAAQ,WAAW;AACpB"}
@@ -1,14 +1,8 @@
1
1
  import type { BrowserCallOptions } from '@orkestrel/browser';
2
2
  import type { BrowserElementInterface } from '@orkestrel/browser';
3
3
  import type { BrowserElementManagerInterface } from '@orkestrel/browser';
4
- import type { BrowserElementQuery } from '@orkestrel/browser';
5
- import type { BrowserEpochFunction } from '@orkestrel/browser';
6
- import type { BrowserOutline } from '@orkestrel/browser';
7
- import type { BrowserOutlineOptions } from '@orkestrel/browser';
8
4
  import type { BrowserReadingInput } from '@orkestrel/browser';
9
5
  import type { BrowserReadingInterface } from '@orkestrel/browser';
10
- import type { BrowserToolsetInterface } from '@orkestrel/browser';
11
- import type { BrowserToolsetOptions } from '@orkestrel/browser';
12
6
  import type { BrowserViewInterface } from '@orkestrel/browser';
13
7
  import type { BrowserWaitOptions } from '@orkestrel/browser';
14
8
  import type { CDPTransportEventMap } from '@orkestrel/browser';
@@ -77,82 +71,6 @@ export declare const BROWSER_SELECTED_ROLES: ReadonlySet<string>;
77
71
  /** Names the `input` type states whose value an untrusted `fill` sets as typed text. */
78
72
  export declare const BROWSER_TYPED_INPUTS: ReadonlySet<string>;
79
73
 
80
- /**
81
- * Configures a toolset that drives one browser document.
82
- *
83
- * @remarks
84
- * - `document` and `own` — the driven document and the admission of the realm's own document, as
85
- * {@link BrowserDOMViewOptions} describes them
86
- * - `source` — a source of page tools, such as `@orkestrel/mcp`'s model context bridge; the
87
- * toolset adopts its tools and re-adopts on its `change`. Default: no page tools
88
- * - `tools`, `limit`, `journeys`, `on`, and `error` — as {@link BrowserToolsetOptions}
89
- * describes them
90
- */
91
- export declare interface BrowserDocumentToolsetOptions extends BrowserDOMViewOptions, Pick<BrowserToolsetOptions, 'on' | 'error' | 'tools' | 'source' | 'limit' | 'journeys'> {
92
- }
93
-
94
- /**
95
- * Drives a referenced element of a DOM document without trusted input.
96
- *
97
- * @remarks
98
- * `click` runs `HTMLElement.click()`; `fill` and `select` set the control through its native
99
- * prototype setter and dispatch `input` and `change`, and `fill` refuses `UNKNOWN` an element
100
- * that is not a text control and a read-only one; `submit` runs `form.requestSubmit()` and
101
- * observes the outcome through a `submit` listener registered across the call. Each action
102
- * refuses with a `BrowserElementError` naming the reason: `DISABLED` for a disabled control,
103
- * `HIDDEN` for an element that does not render, and `UNTRUSTED` for what an untrusted event
104
- * cannot do, which is a click or submission that opens another browsing context, a click that
105
- * opens a file chooser, and typing into a contenteditable element. A click that activates a
106
- * `label`, on the label itself or on a descendant that `matchesBrowserActivation` admits, is
107
- * judged by the label's control as well: a disabled control refuses `DISABLED`, and a file input
108
- * refuses `UNTRUSTED` as a direct click on it does. A click on an interactive descendant of a
109
- * label keeps only its own checks. `role` and `name` read the description the latest outline or
110
- * query that encountered the element captured, so a change to the element shows after the next
111
- * capture, and a dropped reference keeps its last capture. Every action on an element removed
112
- * from its document, collected, or held across a navigation reports `GONE`.
113
- *
114
- * @example
115
- * ```ts
116
- * const view = createBrowserDOMView({ document: frame.contentDocument })
117
- * await view.elements.outline()
118
- * await view.elements.element('e1')?.click()
119
- * ```
120
- */
121
- export declare class BrowserDOMElement implements BrowserDOMElementInterface {
122
- #private;
123
- constructor(input: BrowserDOMElementInput);
124
- get reference(): string;
125
- get role(): string;
126
- get name(): string;
127
- click(options?: BrowserCallOptions): Promise<void>;
128
- fill(value: string, options?: BrowserCallOptions): Promise<void>;
129
- select(values: readonly string[], options?: BrowserCallOptions): Promise<void>;
130
- focus(options?: BrowserCallOptions): Promise<void>;
131
- read(options?: BrowserCallOptions): Promise<BrowserReadingInterface>;
132
- submit(options?: BrowserCallOptions): Promise<void>;
133
- }
134
-
135
- /**
136
- * Binds a DOM element to its reference and the manager that minted it.
137
- *
138
- * @remarks
139
- * - `reference` — the reference the manager minted for the element
140
- * - `description` — returns the role and accessible name the latest capture that encountered
141
- * the element recorded; after the manager drops the reference it keeps returning that capture
142
- * - `node` — a weak reference to the element the reference names, so a removed element can be
143
- * collected; an element that no longer dereferences reports `GONE`
144
- * - `current` — true while the manager still holds the reference; false otherwise
145
- * - `navigation` — reads the epoch of the element's own document, which every reading records;
146
- * it advances when that document or the view's document navigates
147
- */
148
- export declare interface BrowserDOMElementInput {
149
- readonly reference: string;
150
- readonly description: () => Pick<BrowserElementInterface, 'role' | 'name'>;
151
- readonly node: WeakRef<Element>;
152
- readonly current: () => boolean;
153
- readonly navigation: BrowserEpochFunction;
154
- }
155
-
156
74
  /**
157
75
  * Provides DOM actions through a stable element reference, without trusted input.
158
76
  *
@@ -165,71 +83,6 @@ export declare interface BrowserDOMElementInput {
165
83
  export declare interface BrowserDOMElementInterface extends BrowserElementInterface {
166
84
  }
167
85
 
168
- /**
169
- * Outlines a DOM document from its elements and binds stable references to the interactive ones.
170
- *
171
- * @remarks
172
- * Rows come in document order from a `TreeWalker` over the flat tree: an open shadow root
173
- * contributes its rows in place of its host's children, a `slot` its assigned nodes, and a
174
- * same-origin `iframe` its document's rows, while a cross-origin one renders
175
- * `iframe "NAME" (cross-origin, not readable)`. An element that `matchesBrowserHidden` reports is
176
- * omitted with its subtree, a scope root in such a subtree yields no row, and an element that
177
- * `matchesBrowserInvisible` reports yields no row of its own. An element whose role
178
- * `BROWSER_INTERACTIVE_ROLES` names receives a reference bound through a `WeakRef`, which never
179
- * changes while the manager holds it, and a reference number is never reused. Every outline or
180
- * query that encounters a bound element records its role and name afresh, and the element's
181
- * wrapper reports that latest capture, also after the manager drops the reference. A reference
182
- * and a reading from any walked document record that document's epoch, which advances on its own
183
- * navigation events and on the view's; that document's `pagehide` drops its references. A form
184
- * carrying a `toolname` attribute renders `[tool=NAME]` after its role and name. A row carries
185
- * `focused` when its element is the active element of its own document or shadow root. Rows carry
186
- * pressed, expanded, and selected states through the Chromium mapping in `readBrowserStates`.
187
- * A `select` row is followed by one `option` row per option, named by its label. Whitespace between two texts of
188
- * one block renders as one space, as a rendered `br` between them does, and texts with neither
189
- * between them stay joined. A CSS query
190
- * searches the document the view drives, not its child documents or shadow trees. After the
191
- * input's `signal` aborts, `outline`, `find`, and `wait` reject with its reason.
192
- *
193
- * `wait` parks a `BrowserDOMWait` bound to the view's lifetime over every root that
194
- * `collectBrowserRoots` reaches from its scope, reconciled at every observed mutation and frame
195
- * `load`. A shadow root attached after the wait began is a declared limit: the wait discovers it
196
- * at the next observed mutation or `load`, so a match inserted there with no other observed
197
- * change is not seen before the deadline.
198
- *
199
- * @example
200
- * ```ts
201
- * const view = createBrowserDOMView({ document: frame.contentDocument })
202
- * const outline = await view.elements.outline()
203
- * const [save] = await view.elements.find({ role: 'button', name: 'save' })
204
- * ```
205
- */
206
- export declare class BrowserDOMElementManager implements BrowserElementManagerInterface<BrowserDOMElementInterface> {
207
- #private;
208
- constructor(input: BrowserDOMElementManagerInput);
209
- outline(options?: BrowserOutlineOptions): Promise<BrowserOutline>;
210
- find(query: BrowserElementQuery, options?: BrowserCallOptions): Promise<readonly BrowserDOMElementInterface[]>;
211
- wait(query: BrowserElementQuery, options?: BrowserWaitOptions): Promise<readonly BrowserDOMElementInterface[]>;
212
- element(reference: string): BrowserDOMElementInterface | undefined;
213
- elements(): readonly BrowserDOMElementInterface[];
214
- clear(): void;
215
- }
216
-
217
- /**
218
- * Binds a DOM element manager to the view that owns it.
219
- *
220
- * @remarks
221
- * - `document` — returns the document the view drives at the moment of the call
222
- * - `navigation` — reads the view's navigation epoch, which every reading records
223
- * - `signal` — the view's lifetime; it aborts when the view is destroyed, every wait and
224
- * navigation listener the manager starts ends with it, and after it aborts `outline`, `find`,
225
- * and `wait` reject with its reason
226
- */
227
- export declare interface BrowserDOMElementManagerInput {
228
- readonly document: () => Document;
229
- readonly navigation: BrowserEpochFunction;
230
- readonly signal: AbortSignal;
231
- }
232
-
233
86
  /**
234
87
  * Reads and drives a DOM document from a realm that can reach it, without trusted input.
235
88
  *
@@ -242,7 +95,7 @@ export declare interface BrowserDOMElementManagerInput {
242
95
  * fires none of those events, so a reading there stays current across it. A cross-document
243
96
  * navigation also clears every element reference. `destroy()` releases the listeners and every
244
97
  * reference, and fails every pending wait with a `BrowserError` coded
245
- * `BROWSER_DOCUMENT_DESTROYED`; after it, `title()`, `read()`, `wait()`, and the element manager's
98
+ * `DOCUMENT_DESTROYED`; after it, `title()`, `read()`, `wait()`, and the element manager's
246
99
  * `outline()`, `find()`, and `wait()` reject with that error, and a second `destroy()` does
247
100
  * nothing more. `trusted` is `false`: no action grants user activation, and
248
101
  * every event the view's actions dispatch themselves carries `isTrusted` `false`. The `submit`
@@ -302,7 +155,7 @@ export declare interface BrowserDOMViewOptions {
302
155
  * again after every subscription, and no check runs once the deadline, counted from `start`, has
303
156
  * passed, which the wait reads again after `roots` returns. The wait settles one time: on the
304
157
  * check's first value, on the signal's abort with its reason, at the deadline with
305
- * `BROWSER_WAIT_TIMEOUT`, on a `pagehide` in the first root's window with `GONE`, or with whatever
158
+ * `TIMEOUT`, on a `pagehide` in the first root's window with `GONE`, or with whatever
306
159
  * the check or the roots function throws. A signal that aborts while `check` or `roots` runs
307
160
  * settles the wait with its reason, and wins over a value that same check returns. Settlement
308
161
  * disconnects every observer and removes every listener synchronously, so a mutation queued
@@ -506,8 +359,8 @@ export declare function computeBrowserText(root: Element | ShadowRoot, context?:
506
359
  * @param options - The driven document, and `own` to admit the realm's own document
507
360
  * @returns A {@link BrowserDOMViewInterface} over the document's window
508
361
  * @throws Thrown when `document` is not a document attached to a window, with the code
509
- * `BROWSER_DOCUMENT`, and when it is `globalThis.document` without `own: true`, with the code
510
- * `BROWSER_DOCUMENT_OWN`.
362
+ * `DOCUMENT`, and when it is `globalThis.document` without `own: true`, with the code
363
+ * `DOCUMENT_OWN`.
511
364
  *
512
365
  * @example
513
366
  * ```ts
@@ -519,37 +372,6 @@ export declare function computeBrowserText(root: Element | ShadowRoot, context?:
519
372
  */
520
373
  export declare function createBrowserDOMView(options: BrowserDOMViewOptions): BrowserDOMViewInterface;
521
374
 
522
- /**
523
- * Creates a `BrowserToolsetInterface` that publishes the five view tools over a DOM document and
524
- * adopts a source's page tools beside them.
525
- *
526
- * @remarks
527
- * The toolset runs over a view {@link createBrowserDOMView} creates for `document`, so it
528
- * advertises `look`, `read`, `plain`, `click`, `type`, and `wait`, and a click or type receipt ends with
529
- * ` (untrusted event)`. `source` supplies page tools, which the toolset adopts during `start()`
530
- * and again on every `change`; `toolset.native` never includes them, so publishing it to a
531
- * registry leaves that registry's own tools alone. The view belongs to the toolset: `destroy()`
532
- * removes the toolset's tools, then destroys the view, which releases its listeners and fails
533
- * its pending waits, and a construction that throws destroys the view before it rethrows.
534
- * `journeys` adds `record`, `save`, `journeys`, `edit`, and `replay` at construction; a replay
535
- * runs the steps the document placement executes.
536
- *
537
- * @param options - The driven document, `own`, the page-tool source, the manager, the bound, the
538
- * journey stores, and the emitter hooks
539
- * @returns A {@link BrowserToolsetInterface} whose `view` drives the document
540
- * @throws Thrown when `document` is not a document attached to a window, with the code
541
- * `BROWSER_DOCUMENT`, when it is `globalThis.document` without `own: true`, with the code
542
- * `BROWSER_DOCUMENT_OWN`, and when `limit` is not a positive integer.
543
- *
544
- * @example
545
- * ```ts
546
- * const toolset = createDocumentToolset({ document: frame.contentDocument, source: bridge })
547
- * await toolset.start()
548
- * await toolset.tools.execute({ id: '1', name: 'look', arguments: { search: 'form' } })
549
- * ```
550
- */
551
- export declare function createDocumentToolset(options: BrowserDocumentToolsetOptions): BrowserToolsetInterface;
552
-
553
375
  /**
554
376
  * Creates a CDP transport over the browser's native `WebSocket`.
555
377
  *
@@ -752,7 +574,7 @@ export declare function readBrowserBlock(element: Element | null, root: Node): N
752
574
  * @param node - The root whose rendered markup is captured; its owner document supplies `URL`
753
575
  * and `title`
754
576
  * @returns The capture's `url`, `title`, and `html`
755
- * @throws Thrown as a `BrowserResultLimitError` when the serialized capture is longer than
577
+ * @throws Thrown as a `BrowserError` when the serialized capture is longer than
756
578
  * `BROWSER_RESULT_LIMIT` characters, with `length` and `limit` in its context.
757
579
  */
758
580
  export declare function readBrowserCapture(node: Element): BrowserReadingInput;
@@ -855,7 +677,7 @@ export declare function skipBrowserSubtree(walker: TreeWalker): Node | null;
855
677
  * Provides a raw CDP text transport over the browser's native `WebSocket`.
856
678
  *
857
679
  * @remarks
858
- * `start()` resolves on the socket's `open` event and rejects with a `BrowserConnectionError`
680
+ * `start()` resolves on the socket's `open` event and rejects with a `BrowserError`
859
681
  * carrying `url` for a URL whose scheme is not `ws:` or `wss:`, for a URL the `WebSocket`
860
682
  * constructor refuses (one with a fragment), for a socket that fails or closes before it opens,
861
683
  * and at the `timeout` deadline. Concurrent and repeated `start()` and `close()`