@volter-ai-dev/supercode-browser-playwright 0.1.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.
- package/README.md +136 -0
- package/bin/supercode-browser-playwright +7 -0
- package/dist/cli.d.ts +7 -0
- package/dist/executor.d.ts +66 -0
- package/dist/executor.mjs +475 -0
- package/dist/executor.mjs.map +7 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +1016 -0
- package/dist/index.mjs.map +7 -0
- package/dist/protocol.d.ts +90 -0
- package/dist/protocol.mjs +216 -0
- package/dist/protocol.mjs.map +7 -0
- package/dist/provider.d.ts +31 -0
- package/dist/serve.d.ts +32 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Supercode browser provider over Playwright
|
|
2
|
+
|
|
3
|
+
`@volter-ai-dev/supercode-browser-playwright` is a Supercode browser provider
|
|
4
|
+
that is an unmodified `playwright-core` client. It connects to a CDP endpoint
|
|
5
|
+
with `chromium.connectOverCDP`, drives the first page of the first context, and
|
|
6
|
+
answers Supercode's existing wire unchanged: `supercode/browser-provider-v1`
|
|
7
|
+
envelopes carrying `supercode/browser-operation-v1` calls.
|
|
8
|
+
|
|
9
|
+
The package owns that wire: the operation vocabulary, input parsers, results
|
|
10
|
+
and error codes (`./protocol`). Every locator, action and snapshot is
|
|
11
|
+
playwright-core 1.63.0's own, with Playwright's actionability waits.
|
|
12
|
+
|
|
13
|
+
## Operations
|
|
14
|
+
|
|
15
|
+
All 21 operations:
|
|
16
|
+
|
|
17
|
+
| Operation | Over Playwright |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `browser.status` | `{available, features, syntheticEvents, implementation: "playwright-core 1.63.0", endpoint: browser.version()}` |
|
|
20
|
+
| `browser.snapshot` | `ariaSnapshot({mode: "ai"})` of the page or the locator's first match, bounded to 64 000 characters |
|
|
21
|
+
| `browser.query` | `count()` and up to 50 inspections |
|
|
22
|
+
| `browser.wait` | `locator.waitFor`, clamped to 9 s |
|
|
23
|
+
| `browser.click` `fill` `press` `hover` `focus` `check` `uncheck` | the locator action with a 5 s actionability budget; the result is the element's inspection |
|
|
24
|
+
| `browser.select` | `selectOption`, returning the selected values |
|
|
25
|
+
| `browser.scroll` | `scrollBy` in the page, returning `scrollX`/`scrollY` |
|
|
26
|
+
| `browser.box` | `boundingBox()` |
|
|
27
|
+
| `browser.mouse` `wheel` `drag` | `page.mouse` |
|
|
28
|
+
| `browser.back` `forward` `reload` | `goBack`/`goForward`/`reload`, waiting for commit |
|
|
29
|
+
| `browser.script` | the author's source as `async (page, args)` with the real `page`, clamped to 9 s |
|
|
30
|
+
|
|
31
|
+
Locators map one to one onto `page.locator`, `getByRole`, `getByText`,
|
|
32
|
+
`getByTestId`, `getByLabel`, `getByPlaceholder`, `getByAltText` and
|
|
33
|
+
`getByTitle`. A `{by: "ref"}` locator is a `[ref=…]` mark from
|
|
34
|
+
`browser.snapshot`'s AI-mode aria snapshot, resolved by Playwright's `aria-ref`
|
|
35
|
+
selector engine. An inspection's `ref` is the element's own aria ref, or `""`
|
|
36
|
+
when Playwright assigns it none (an element that is not visible or does not
|
|
37
|
+
receive pointer events).
|
|
38
|
+
|
|
39
|
+
The page revision is a mutation counter kept in the page by a
|
|
40
|
+
`MutationObserver` installed with `page.addInitScript`; a navigation starts a
|
|
41
|
+
new document and so a new count. Playwright timeouts are `TIMED_OUT`, a closed
|
|
42
|
+
page or disconnected browser is `NOT_AVAILABLE`, a strict-mode violation or a
|
|
43
|
+
locator matching nothing is `NOT_FOUND`, a protocol error that says
|
|
44
|
+
"unavailable" or "not supported" is `UNSUPPORTED`, anything else `FAILED`.
|
|
45
|
+
|
|
46
|
+
The harness abandons a provider call at 12 s, so a script's timeout (default
|
|
47
|
+
30 s on the wire) is clamped to 9 s and the result says so in `notice`. A
|
|
48
|
+
script that outlives its deadline keeps running in the provider process; the
|
|
49
|
+
call still returns. Listeners a script attaches to `page` are removed when it
|
|
50
|
+
ends. A PNG a script returns (`await page.screenshot()`) crosses the wire as
|
|
51
|
+
an image record `{dataUrl, format, width, height, fidelity}`, bounded
|
|
52
|
+
to 768 KiB of data URL.
|
|
53
|
+
|
|
54
|
+
## Framings
|
|
55
|
+
|
|
56
|
+
Both carry the same envelope, `{protocol, id, token, call}` in and
|
|
57
|
+
`{protocol, id, result}` out, with a 256 KiB request and 1 MiB response bound.
|
|
58
|
+
|
|
59
|
+
- **TCP** is the wire the harness speaks (`crates/harness/src/browser.rs`): one
|
|
60
|
+
newline-terminated JSON request per connection, one JSON response, then the
|
|
61
|
+
provider closes. The provider listens on `127.0.0.1` and writes an owner-only
|
|
62
|
+
discovery record (file `0600`, directory `0700`) to
|
|
63
|
+
`<providers dir>/browser/playwright.cdp.<port>.json`, scoped to the
|
|
64
|
+
canonical workspace, and removes it on stop.
|
|
65
|
+
- **HTTP** serves `POST /` with the request JSON as the body and answers `200`
|
|
66
|
+
with the response JSON, for a host that can reach the provider only by HTTP.
|
|
67
|
+
Other paths are `404`, other methods `405`, a body that is not JSON `400`,
|
|
68
|
+
an oversized one `413`.
|
|
69
|
+
|
|
70
|
+
Calls are answered one at a time. If the browser disconnected or the page
|
|
71
|
+
closed, the provider reconnects once for the call and otherwise answers
|
|
72
|
+
`NOT_AVAILABLE`.
|
|
73
|
+
|
|
74
|
+
## CLI
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
supercode-browser-playwright --cdp-url http://127.0.0.1:9222 --tcp 0 --workspace .
|
|
78
|
+
supercode-browser-playwright --cdp-url ws://127.0.0.1:9222/devtools/browser/… --http 8765 --token <hex>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
--cdp-url <url> CDP endpoint (http:// resolved through /json/version, or ws://)
|
|
83
|
+
--tcp <port> the harness framing; 0 picks a free port
|
|
84
|
+
--providers-dir <dir> parent of browser/ (default: $SUPERCODE_HOME/providers, then
|
|
85
|
+
$XDG_CONFIG_HOME/supercode/providers, then ~/.config/supercode/providers)
|
|
86
|
+
--workspace <path> workspace the discovery record is scoped to (default: cwd)
|
|
87
|
+
--http <port> the HTTP framing; --token is required, the host passes it
|
|
88
|
+
--token <hex> at least 32 hex characters (default: 32 random bytes)
|
|
89
|
+
--synthetic-events the endpoint dispatches isTrusted:false input (an AlmostCDP endpoint)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
When listening it prints one JSON line, `{"listening":{"framing":"tcp","port":…}}`.
|
|
93
|
+
|
|
94
|
+
## Fidelity
|
|
95
|
+
|
|
96
|
+
`browser.status` and the discovery record report `playwright-core 1.63.0` and
|
|
97
|
+
the endpoint's `browser.version()`. `syntheticEvents` comes from
|
|
98
|
+
`--synthetic-events`: native Chrome dispatches trusted input for CDP `Input.*`
|
|
99
|
+
commands, an AlmostCDP endpoint dispatches `isTrusted: false` DOM events, and
|
|
100
|
+
the provider cannot tell the two apart itself. `browser.script` runs with
|
|
101
|
+
the full Playwright `Page`, including `page.evaluate`: allowing it trusts the
|
|
102
|
+
agent with the page and the provider process.
|
|
103
|
+
|
|
104
|
+
## Library
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { createPlaywrightBrowserProvider, serveTcp } from '@volter-ai-dev/supercode-browser-playwright';
|
|
108
|
+
|
|
109
|
+
const provider = createPlaywrightBrowserProvider({
|
|
110
|
+
cdpUrl: 'http://127.0.0.1:9222',
|
|
111
|
+
token: crypto.randomBytes(32).toString('hex'),
|
|
112
|
+
syntheticEvents: false,
|
|
113
|
+
});
|
|
114
|
+
const server = await serveTcp(provider, { port: 0, syntheticEvents: false });
|
|
115
|
+
// provider.handle(request) answers one envelope without any framing.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## In a browser
|
|
119
|
+
|
|
120
|
+
Two entry points use no Node API:
|
|
121
|
+
|
|
122
|
+
- `@volter-ai-dev/supercode-browser-playwright/protocol`: the wire alone
|
|
123
|
+
(`parseBrowserOperationCall`, `parseBrowserOperationResult`, the protocol
|
|
124
|
+
names, `BrowserActionRefusal`), with no dependency, for a host that relays
|
|
125
|
+
calls.
|
|
126
|
+
- `@volter-ai-dev/supercode-browser-playwright/executor`:
|
|
127
|
+
`PlaywrightOperationExecutor` over any Playwright `Page`. It imports
|
|
128
|
+
`playwright-core`; a browser host aliases that to a browser build of it,
|
|
129
|
+
`@volter/almostcdp/playwright`, and answers the operations against an
|
|
130
|
+
AlmostCDP surface with no Node process.
|
|
131
|
+
|
|
132
|
+
A host's `actionGuard(action)` is asked before each locator action (`click`,
|
|
133
|
+
`fill`, `press`, `hover`, `focus`, `check`, `uncheck`, `select`, `drag`) with
|
|
134
|
+
the action's `Locator` and value; throwing a `BrowserActionRefusal` answers the
|
|
135
|
+
call with its code, such as `APPROVAL_REQUIRED`. `browser.script` is not
|
|
136
|
+
guarded: a script is trusted with the page.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `supercode-browser-playwright --cdp-url <url>
|
|
3
|
+
* (--tcp <port> [--providers-dir <dir>] [--workspace <path>] | --http <port>)
|
|
4
|
+
* [--token <hex>] [--synthetic-events]`
|
|
5
|
+
*/
|
|
6
|
+
import { type ServeHandle } from "./serve.js";
|
|
7
|
+
export declare function main(argv: readonly string[]): Promise<ServeHandle>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supercode's `supercode/browser-operation-v1` calls over a real Playwright
|
|
3
|
+
* `Page`: every locator, action and snapshot is playwright-core's own, driven
|
|
4
|
+
* over CDP. No Node API is used, so the executor also runs in a browser realm
|
|
5
|
+
* with a browser build of playwright-core (`@volter/almostcdp/playwright`).
|
|
6
|
+
*/
|
|
7
|
+
import { type Locator, type Page } from "playwright-core";
|
|
8
|
+
import { type BrowserOperationErrorCode, type BrowserOperationResult } from "./protocol.js";
|
|
9
|
+
/** The implementation this provider reports; the pinned playwright-core. */
|
|
10
|
+
export declare const PLAYWRIGHT_IMPLEMENTATION = "playwright-core 1.63.0";
|
|
11
|
+
/** The harness abandons a provider call at 12 s; a script must end before that. */
|
|
12
|
+
export declare const SCRIPT_TIMEOUT_CLAMP_MS = 9000;
|
|
13
|
+
/** Actionability budget for one locator action. */
|
|
14
|
+
export declare const ACTION_TIMEOUT_MS = 5000;
|
|
15
|
+
/** `browser.wait` accepts 30 s on the wire; the harness deadline caps what can be honoured. */
|
|
16
|
+
export declare const WAIT_TIMEOUT_CLAMP_MS = 9000;
|
|
17
|
+
/** The Playwright features `browser.status` reports. */
|
|
18
|
+
export declare const PLAYWRIGHT_FEATURES: readonly string[];
|
|
19
|
+
export interface PlaywrightOperationExecutorOptions {
|
|
20
|
+
/** True when the endpoint dispatches `isTrusted:false` input (an AlmostCDP endpoint); false for native Chrome. */
|
|
21
|
+
syntheticEvents: boolean;
|
|
22
|
+
/** `browser.version()` of the connected endpoint, reported by `browser.status`. */
|
|
23
|
+
endpoint: string;
|
|
24
|
+
/**
|
|
25
|
+
* The host's policy for one locator action, asked before it runs; throwing
|
|
26
|
+
* a `BrowserActionRefusal` refuses it with that code. `browser.script` is
|
|
27
|
+
* not guarded: a script is trusted with the page.
|
|
28
|
+
*/
|
|
29
|
+
actionGuard?: (action: PlaywrightAction) => void | Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/** One locator action an operation is about to perform. */
|
|
32
|
+
export interface PlaywrightAction {
|
|
33
|
+
action: "click" | "fill" | "press" | "hover" | "focus" | "check" | "uncheck" | "select" | "drag";
|
|
34
|
+
locator: Locator;
|
|
35
|
+
value?: unknown;
|
|
36
|
+
}
|
|
37
|
+
/** Map a Playwright failure onto the wire's error codes. */
|
|
38
|
+
export declare function classifyPlaywrightError(error: unknown): BrowserOperationErrorCode;
|
|
39
|
+
export declare class PlaywrightOperationExecutor {
|
|
40
|
+
private readonly page;
|
|
41
|
+
private readonly options;
|
|
42
|
+
private readonly ready;
|
|
43
|
+
constructor(page: Page, options: PlaywrightOperationExecutorOptions);
|
|
44
|
+
execute(raw: unknown): Promise<BrowserOperationResult>;
|
|
45
|
+
private locator;
|
|
46
|
+
/**
|
|
47
|
+
* Playwright's `aria-ref` engine resolves against the last AI-mode snapshot
|
|
48
|
+
* the page took. Refs are stable per element, so refreshing the whole-page
|
|
49
|
+
* snapshot before resolving one keeps every ref from `browser.snapshot`
|
|
50
|
+
* addressable even after an element-scoped snapshot replaced the map.
|
|
51
|
+
*/
|
|
52
|
+
private refreshRefs;
|
|
53
|
+
private refOf;
|
|
54
|
+
private inspectAll;
|
|
55
|
+
private inspect;
|
|
56
|
+
/** Run a locator action; a failure on a locator that matches nothing is NOT_FOUND. */
|
|
57
|
+
private act;
|
|
58
|
+
/** The host's policy for an action; an element that is not there is the action's own failure. */
|
|
59
|
+
private guard;
|
|
60
|
+
private revision;
|
|
61
|
+
private executeCall;
|
|
62
|
+
private script;
|
|
63
|
+
private target;
|
|
64
|
+
private success;
|
|
65
|
+
private failure;
|
|
66
|
+
}
|