effing-use 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/LICENSE +21 -0
- package/README.md +112 -0
- package/package.json +52 -0
- package/skills/effing-use/SKILL.md +58 -0
- package/skills/effing-use/references/setup.md +89 -0
- package/skills/effing-use/references/troubleshooting.md +64 -0
- package/src/browser/engine.ts +712 -0
- package/src/browser/output.ts +31 -0
- package/src/browser/refs.ts +75 -0
- package/src/browser/session.ts +100 -0
- package/src/config.ts +25 -0
- package/src/http.ts +28 -0
- package/src/index.ts +6 -0
- package/src/server.ts +19 -0
- package/src/tools/act.ts +131 -0
- package/src/tools/extract.ts +86 -0
- package/src/tools/observe.ts +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Obubelebra Amachree
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# effing-use — stop paying 19.5 KB every session for browser control
|
|
2
|
+
|
|
3
|
+
Full Chromium automation in **3 tools, 3.9 KB**. Same pages, same clicks, same scrapes — without the 24-tool handshake eating your context window before you load a page.
|
|
4
|
+
|
|
5
|
+
**Measured, not marketed:** `tools/list` is **3,913 bytes** here vs **19,517 bytes** for `@playwright/mcp@latest` (~5x smaller, ~15.6 KB saved every session). Local ops stay in milliseconds — snapshot ~15 ms, extract ~50 ms, batch ~65 ms, screenshot ~60–190 ms. Page loads still cost seconds (network, not us). Full numbers in [`docs/COMPARISON.md`](docs/COMPARISON.md).
|
|
6
|
+
|
|
7
|
+
## Install (Bun-only)
|
|
8
|
+
|
|
9
|
+
Requires [Bun](https://bun.sh) 1.4+. The `playwright` npm package ships the driver, **not** the browser — every user needs Playwright's version-pinned Chromium (~150 MB) once:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bunx effing-use --help # after: bun publish (runs src/index.ts via bin)
|
|
13
|
+
# or from source:
|
|
14
|
+
bun install
|
|
15
|
+
bunx playwright install chromium --only-shell # one-time Chromium download
|
|
16
|
+
bun src/index.ts # STDIO (single editor)
|
|
17
|
+
bun src/http.ts # HTTP on :3000 (/mcp) — shared across editors
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Re-run `bunx playwright install chromium --only-shell` whenever you bump the `playwright` dependency (each Playwright version pins its own browser build). Verify with `bunx playwright install --dry-run chromium` or check `~/.cache/ms-playwright/`.
|
|
21
|
+
|
|
22
|
+
**Why Chromium is separate:** Playwright supports multiple browsers and updates its pinned builds every release, so the binary can't live inside the npm tarball (ours is 16 kB). Docker users skip this — Chromium is baked into the `mcr.microsoft.com/playwright` base image.
|
|
23
|
+
|
|
24
|
+
## Run it in 60 seconds (recommended path)
|
|
25
|
+
|
|
26
|
+
**Step 1/3 — Start the server.** One server, every local editor:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bun install
|
|
30
|
+
bunx playwright install chromium --only-shell
|
|
31
|
+
docker compose up --build -d
|
|
32
|
+
curl http://localhost:3000/healthz
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Point any VS Code instance at `http://localhost:3000/mcp` (see `.vscode/mcp.json` → `effing-use (http)`). Plain HTTP on loopback is intentional — add TLS at the edge for remote use.
|
|
36
|
+
|
|
37
|
+
**Step 2/3 — Connect.** STDIO for one editor, HTTP for all of them:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"computer-use": {
|
|
43
|
+
"command": "bun",
|
|
44
|
+
"args": ["/path/to/litepilot/src/index.ts"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or HTTP: `http://localhost:3000/mcp`.
|
|
51
|
+
|
|
52
|
+
**Step 3/3 — Drive.** Search Wikipedia in one call instead of two round-trips:
|
|
53
|
+
|
|
54
|
+
```jsonc
|
|
55
|
+
// browser_act batch: fill + press in 65 ms measured
|
|
56
|
+
{
|
|
57
|
+
"action": "batch",
|
|
58
|
+
"steps": [
|
|
59
|
+
{ "action": "fill", "target": "input[name=search]", "value": "Playwright" },
|
|
60
|
+
{ "action": "press", "target": "input[name=search]", "value": "Enter" },
|
|
61
|
+
],
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
No Docker? `bun src/index.ts` (STDIO) or `bun src/http.ts` (`:3000` `/mcp`) works directly.
|
|
66
|
+
|
|
67
|
+
## Why agents prefer 3 tools
|
|
68
|
+
|
|
69
|
+
- 🪶 **Tiny handshake, full surface** — `browser_act` (27 actions), `browser_observe` (8 kinds), `browser_extract` (7 kinds). No schema bloat, no guessing which of 24 tools to call.
|
|
70
|
+
- 🧠 **Context-safe by default** — snapshots capped at `OUTPUT_MAX_CHARS` (default 4000); full YAML/text saved under `.browser-use/`, never dumped inline. HN snapshot: 4,034-char preview, full file on disk.
|
|
71
|
+
- 🖼️ **File paths, not base64** — screenshots, PDFs, traces return paths like `.browser-use/shot-*.png`. Read the file only when needed.
|
|
72
|
+
- ⚡ **One call, not five** — `batch` runs fill+press flows in one turn (max 20 steps, stops on first error). `goal` plans or returns `E_GOAL_UNCLEAR` + `suggestedSteps` instead of hallucinating.
|
|
73
|
+
- 🐳 **Shared, not spawned** — one Docker server serves every local VS Code instance. No per-client `npx` spawn.
|
|
74
|
+
|
|
75
|
+
## The loop (agents: follow this order)
|
|
76
|
+
|
|
77
|
+
1. `browser_observe` kind=`snapshot` → get `[eN]` refs (never guess refs, re-snapshot after navigation)
|
|
78
|
+
2. `browser_act` to interact — prefer `batch` with `steps[]`
|
|
79
|
+
3. `browser_observe` kind=`screenshot` → verify visually (you get a path)
|
|
80
|
+
4. `browser_extract` kind=`text`|`table`|`query` → scrape structured data
|
|
81
|
+
|
|
82
|
+
## Tools
|
|
83
|
+
|
|
84
|
+
- `browser_act` — open/goto, click, dblclick, fill, type, press, select, check/uncheck, hover, drag, upload, scroll, back/forward/reload, wait, dialog_accept/dismiss, tabs (new/select/close), resize, close, `goal`, `batch`
|
|
85
|
+
- `browser_observe` — snapshot (e-refs), screenshot (path), url, title, console (last N), network (method/url/status ring), tabs, focused
|
|
86
|
+
- `browser_extract` — text, html, table (≤100 rows JSON), query (text|href|json), pdf, trace_start/stop
|
|
87
|
+
|
|
88
|
+
Errors are always `{ ok: false, code, message, hint }` with `E_NOT_FOUND | E_TIMEOUT | E_NO_PAGE | E_BAD_INPUT | E_GOAL_UNCLEAR` — never a stack trace.
|
|
89
|
+
|
|
90
|
+
## effing-use vs Playwright MCP
|
|
91
|
+
|
|
92
|
+
| | effing-use | Playwright MCP |
|
|
93
|
+
| ---------------- | ------------------------------- | ---------------------------------------------------------- |
|
|
94
|
+
| `tools/list` | **3,913 bytes / 3 tools** | **19,517 bytes / 24 tools** |
|
|
95
|
+
| Snapshot | capped 4 KB preview + full file | full accessibility tree |
|
|
96
|
+
| Screenshots/PDFs | file paths | inline or output dir |
|
|
97
|
+
| Browsers | Chromium (headless in Docker) | Chromium, Firefox, WebKit, Edge + vision/pdf/devtools caps |
|
|
98
|
+
|
|
99
|
+
Need Firefox/WebKit, device emulation, or persistent profiles? Use Playwright MCP. Need context budget for Chromium work? Stay here. Full breakdown in [`docs/COMPARISON.md`](docs/COMPARISON.md).
|
|
100
|
+
|
|
101
|
+
## Config
|
|
102
|
+
|
|
103
|
+
Env defaults in [`.env.example`](.env.example): `BROWSER_HEADLESS`, `BROWSER_VIEWPORT_W/H`, `BROWSER_TIMEOUT_MS`, `OUTPUT_DIR` (`.browser-use/`, gitignored), `OUTPUT_MAX_CHARS`, `ALLOW_EVAL`.
|
|
104
|
+
|
|
105
|
+
Agent skill: `skills/effing-use/SKILL.md` (skills.sh-ready).
|
|
106
|
+
|
|
107
|
+
## Verify
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
bunx tsc --noEmit # 0 errors
|
|
111
|
+
bun test # 6 pass
|
|
112
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "effing-use",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Token-efficient browser control: 3 tools (act, observe, extract) built with tmcp + Bun + Playwright",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Michael Obubelebra Amachree",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Michael-Obele/litepilot.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Michael-Obele/litepilot#readme",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "src/index.ts",
|
|
14
|
+
"bin": {
|
|
15
|
+
"effing-use": "src/index.ts",
|
|
16
|
+
"effing-use-http": "src/http.ts"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"src",
|
|
20
|
+
"skills",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"start": "bun src/index.ts",
|
|
26
|
+
"start:http": "bun src/http.ts",
|
|
27
|
+
"dev": "bun --watch src/index.ts",
|
|
28
|
+
"dev:http": "bun --watch src/http.ts",
|
|
29
|
+
"check": "bunx tsc --noEmit",
|
|
30
|
+
"test": "bun test"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"mcp",
|
|
34
|
+
"model-context-protocol",
|
|
35
|
+
"playwright",
|
|
36
|
+
"browser-automation",
|
|
37
|
+
"tmcp",
|
|
38
|
+
"chromium"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@tmcp/adapter-valibot": "^0.1.6",
|
|
42
|
+
"@tmcp/transport-http": "^0.9.0",
|
|
43
|
+
"@tmcp/transport-stdio": "^0.5.0",
|
|
44
|
+
"playwright": "^1.63.0",
|
|
45
|
+
"tmcp": "^1.20.0",
|
|
46
|
+
"valibot": "^1.4.2"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/bun": "latest",
|
|
50
|
+
"typescript": "latest"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: effing-use
|
|
3
|
+
description: Drive a headless Chromium browser through 3 token-efficient MCP tools (browser_act, browser_observe, browser_extract). Use when automating web pages, scraping structured data, screenshotting UIs, filling forms, or testing web flows.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires the effing-use MCP server (Bun + Playwright Chromium). Works over stdio or Streamable HTTP at /mcp.
|
|
6
|
+
metadata:
|
|
7
|
+
repo: Michael-Obele/litepilot
|
|
8
|
+
tools: browser_act,browser_observe,browser_extract
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# effing-use — token-efficient browser control
|
|
12
|
+
|
|
13
|
+
Three tools cover 100% of the interaction surface at ~4–10x lower token
|
|
14
|
+
cost than 21-tool browser servers. `tools/list` is ~3.9KB.
|
|
15
|
+
|
|
16
|
+
## The loop (always follow this order)
|
|
17
|
+
|
|
18
|
+
1. `browser_observe` with `kind: "snapshot"` → get `[eN]` refs.
|
|
19
|
+
2. `browser_act` to interact (`open`, `click`, `fill`, `type`, `press`, `select`, `check`, `wait`, …).
|
|
20
|
+
3. `browser_observe` with `kind: "screenshot"` → verify visually (returns a file path).
|
|
21
|
+
4. `browser_extract` with `kind: "text" | "table" | "query"` → scrape.
|
|
22
|
+
|
|
23
|
+
Rules:
|
|
24
|
+
|
|
25
|
+
- Never guess refs. Re-snapshot after every navigation.
|
|
26
|
+
- Prefer `batch`: one `browser_act` with `steps[]` for fill+press flows (max 20 steps, stops on first error).
|
|
27
|
+
- Large outputs are files under `.browser-use/` (gitignored). Read the path, not the preview.
|
|
28
|
+
- Snapshots are capped at `OUTPUT_MAX_CHARS` (default 4000) with `…[truncated N chars, see file]`.
|
|
29
|
+
|
|
30
|
+
## Tool cheat sheet
|
|
31
|
+
|
|
32
|
+
**browser_act** — `action` + optional `target` (e-ref, `role=` selector, or CSS) + `value`:
|
|
33
|
+
`open`/`goto` (URL in `value`), `click`, `dblclick`, `fill`, `type`,
|
|
34
|
+
`press` (key like `Enter`), `select`, `check`/`uncheck`, `hover`,
|
|
35
|
+
`drag` (start in `target`, end in `value`), `upload` (comma-separated paths in `value`),
|
|
36
|
+
`scroll` (`up`/`down`/`top`/`bottom` or a target), `back`/`forward`/`reload`,
|
|
37
|
+
`wait` (`ms:500`, `text:Saved`, or a ref), `dialog_accept`/`dialog_dismiss` (arm before the triggering step),
|
|
38
|
+
`resize` (`1280x800` in `value`), `tab_new`/`tab_select`/`tab_close`, `close`,
|
|
39
|
+
`goal` (deterministic add-todo/search planner, else `E_GOAL_UNCLEAR` + `suggestedSteps`),
|
|
40
|
+
`batch` (needs `steps[]`).
|
|
41
|
+
|
|
42
|
+
**browser_observe** — read-only: `snapshot` (e-refs), `screenshot` (file path,
|
|
43
|
+
`full` page by default), `url`, `title`, `console` (last N, `limit`),
|
|
44
|
+
`network` (method/url/status ring), `tabs`, `focused` (activeElement HTML).
|
|
45
|
+
|
|
46
|
+
**browser_extract** — `text`, `html`, `table` (≤100 rows as JSON),
|
|
47
|
+
`query` (`selector` + `mode: text|href|json`), `pdf` (headless Chromium only),
|
|
48
|
+
`trace_start`/`trace_stop` (Playwright trace zip).
|
|
49
|
+
|
|
50
|
+
Errors always come back as `{ ok: false, code, message, hint }` with codes
|
|
51
|
+
`E_NOT_FOUND | E_TIMEOUT | E_NO_PAGE | E_BAD_INPUT | E_GOAL_UNCLEAR` — never a stack trace.
|
|
52
|
+
|
|
53
|
+
## Setup
|
|
54
|
+
|
|
55
|
+
See [references/setup.md](references/setup.md) for install (local Bun,
|
|
56
|
+
Docker, VS Code `mcp.json` entries), port config (`ECU_PORT`), and the
|
|
57
|
+
`.browser-use/` gitignore contract. See [references/troubleshooting.md](references/troubleshooting.md)
|
|
58
|
+
for port conflicts, Chromium sandbox notes, and the `doQuery` arity lesson.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Setup — effing-use
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- [Bun](https://bun.sh) 1.4+ (`bun --version`)
|
|
6
|
+
- Docker 29+ with Compose v2 (only for the container route)
|
|
7
|
+
- Chromium system deps — handled by `bunx playwright install chromium`
|
|
8
|
+
locally, or baked into the `mcr.microsoft.com/playwright:v1.63.0-noble`
|
|
9
|
+
base image in Docker.
|
|
10
|
+
|
|
11
|
+
## Option A — local Bun (single VS Code instance)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun install
|
|
15
|
+
bunx playwright install chromium --only-shell
|
|
16
|
+
bun src/index.ts # STDIO transport
|
|
17
|
+
bun src/http.ts # Streamable HTTP on $PORT (default 3000), MCP at /mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
VS Code `.vscode/mcp.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"servers": {
|
|
25
|
+
"effing-use (stdio)": {
|
|
26
|
+
"type": "stdio",
|
|
27
|
+
"command": "bun",
|
|
28
|
+
"args": ["/path/to/effing-use/src/index.ts"],
|
|
29
|
+
"cwd": "/path/to/effing-use",
|
|
30
|
+
"env": {
|
|
31
|
+
"BROWSER_HEADLESS": "true",
|
|
32
|
+
"OUTPUT_DIR": "/path/to/effing-use/.browser-use"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"effing-use (http)": { "type": "http", "url": "http://localhost:3123/mcp" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Option B — Docker (shared across VS Code instances)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
ECU_PORT=3123 docker compose up --build -d
|
|
44
|
+
curl http://localhost:3123/healthz # {"ok":true,"name":"effing-use"}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then point any local client at `http://localhost:<ECU_PORT>/mcp`.
|
|
48
|
+
The container listens on 3000 internally; only the host-side port moves.
|
|
49
|
+
|
|
50
|
+
- `restart: unless-stopped` — survives daemon restarts and host reboots
|
|
51
|
+
once started with `up -d`.
|
|
52
|
+
- `init: true` + `ipc: host` — Playwright's recommended flags (no PID-1
|
|
53
|
+
zombies, no Chromium `/dev/shm` crashes).
|
|
54
|
+
- `.browser-use/` is bind-mounted so snapshots/screenshots land on the host.
|
|
55
|
+
- Plain HTTP on loopback is intentional. For remote use, terminate TLS at
|
|
56
|
+
the edge (reverse proxy, Cloudflare Tunnel, Tailscale) — never bake certs
|
|
57
|
+
into the image.
|
|
58
|
+
|
|
59
|
+
## Environment
|
|
60
|
+
|
|
61
|
+
All optional; defaults shown (see `.env.example`):
|
|
62
|
+
|
|
63
|
+
| Var | Default | Notes |
|
|
64
|
+
| ---------------------- | -------------- | ---------------------------------------------- |
|
|
65
|
+
| `PORT` | `3000` | `src/http.ts` listen port (container-internal) |
|
|
66
|
+
| `ECU_PORT` | `3000` | compose host-side port override |
|
|
67
|
+
| `BROWSER_HEADLESS` | `true` | Docker supports headless Chromium only |
|
|
68
|
+
| `BROWSER_VIEWPORT_W/H` | `1280/800` | |
|
|
69
|
+
| `BROWSER_TIMEOUT_MS` | `15000` | per-action Playwright timeout |
|
|
70
|
+
| `OUTPUT_DIR` | `.browser-use` | all file outputs land here |
|
|
71
|
+
| `OUTPUT_MAX_CHARS` | `4000` | inline cap; full text goes to the file |
|
|
72
|
+
| `ALLOW_EVAL` | `false` | no raw JS eval path unless explicitly enabled |
|
|
73
|
+
|
|
74
|
+
## Gitignore contract
|
|
75
|
+
|
|
76
|
+
`.browser-use/`, `*.png`, `*.pdf`, `node_modules/` stay out of git.
|
|
77
|
+
Any local planning/scratch folder (e.g. `docs/plan/`) should also be gitignored —
|
|
78
|
+
it holds the build spec, not shippable code.
|
|
79
|
+
|
|
80
|
+
## Verify
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
bunx tsc --noEmit # 0 errors
|
|
84
|
+
bun test # unit green
|
|
85
|
+
curl -s -X POST http://localhost:3123/mcp \
|
|
86
|
+
-H 'Content-Type: application/json' \
|
|
87
|
+
-H 'Accept: application/json, text/event-stream' \
|
|
88
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | head -c 300
|
|
89
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Troubleshooting — effing-use
|
|
2
|
+
|
|
3
|
+
## Port already in use
|
|
4
|
+
|
|
5
|
+
Port 3000 is a popular squat (e.g. other MCP servers). Diagnose:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ss -tlnp | grep -E ':3000|:3123'
|
|
9
|
+
docker ps --format "{{.Names}} {{.Ports}}"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Fix — move our host port, never the container's:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
ECU_PORT=3123 docker compose up -d # client → http://localhost:3123/mcp
|
|
16
|
+
PORT=3123 bun src/http.ts # local Bun route
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Chromium won't launch in Docker
|
|
20
|
+
|
|
21
|
+
- Keep `ipc: host` (Chromium crashes on small `/dev/shm` without it).
|
|
22
|
+
- Keep `init: true` (avoids PID-1 zombie processes).
|
|
23
|
+
- Headless only in containers. If you see sandbox errors on untrusted
|
|
24
|
+
sites, run with a non-root user + seccomp profile per
|
|
25
|
+
<https://playwright.dev/docs/docker> (trusted E2E code is fine as root).
|
|
26
|
+
|
|
27
|
+
## `bun: not found` during `docker build`
|
|
28
|
+
|
|
29
|
+
The `curl | bash` Bun installer can break mid-download (`curl: (56)`) yet
|
|
30
|
+
the layer still "succeeds", leaving no binary. The effing-use Dockerfile copies Bun from
|
|
31
|
+
the pinned `oven/bun` image instead — deterministic, no network flakiness:
|
|
32
|
+
|
|
33
|
+
```dockerfile
|
|
34
|
+
COPY --from=oven/bun:1.4.0 /usr/local/bin/bun /usr/local/bin/bun
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Query extract returns `[]`
|
|
38
|
+
|
|
39
|
+
`page.locator(sel).evaluateAll(fn)` does **not** forward outer-scope args —
|
|
40
|
+
the second parameter must be passed explicitly:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
.evaluateAll((els, m: string) => /* … */, mode)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Without it the callback receives `undefined` and (depending on arity
|
|
47
|
+
handling) the call throws inside the page, surfacing as an empty result
|
|
48
|
+
via `.catch(() => [])`. Lesson: always pass `evaluateAll`/`evaluate`
|
|
49
|
+
arguments explicitly; never rely on closure capture across the
|
|
50
|
+
browser boundary.
|
|
51
|
+
|
|
52
|
+
## Stale snapshot refs (`E_NOT_FOUND`)
|
|
53
|
+
|
|
54
|
+
Refs are nth-match positions in DOM order — any navigation or re-render
|
|
55
|
+
invalidates them. Fix: re-run `browser_observe kind: "snapshot"` and use
|
|
56
|
+
fresh `eN` values. Fuzzy matching (`fill` with a label) and `role=`
|
|
57
|
+
selectors survive re-renders better than raw `eN` refs.
|
|
58
|
+
|
|
59
|
+
## Slow external sites timing out
|
|
60
|
+
|
|
61
|
+
Default action timeout is 15s (`BROWSER_TIMEOUT_MS`). For slow demos,
|
|
62
|
+
either raise it or prefer `wait` with `text:` expectations over fixed
|
|
63
|
+
`ms:` sleeps. For deterministic E2E, serve a local fixture
|
|
64
|
+
(`file:///tmp/…`) instead of depending on the network.
|