browserzap 0.6.1 → 0.8.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/CHANGELOG.md +201 -2
- package/README.md +31 -19
- package/THIRD_PARTY_NOTICES.md +4 -3
- package/bridge-server/background-runs.js +1 -1
- package/bridge-server/entitlements.js +8 -6
- package/bridge-server/extension-id.js +64 -1
- package/bridge-server/extension-version.js +65 -0
- package/bridge-server/feedback.js +55 -17
- package/bridge-server/index.js +36 -24
- package/bridge-server/limits.js +21 -2
- package/bridge-server/mcp-server.js +166 -16
- package/bridge-server/native-host.js +22 -3
- package/bridge-server/panel.js +10 -4
- package/bridge-server/probe.js +56 -1
- package/bridge-server/profile-labels.js +81 -0
- package/bridge-server/resolvers.js +1 -1
- package/bridge-server/secret.js +1 -1
- package/bridge-server/server.js +91 -16
- package/bridge-server/setup.js +85 -26
- package/bridge-server/tools.js +46 -2
- package/package.json +17 -7
- package/extension/background.js +0 -1
- package/extension/engine.js +0 -1
- package/extension/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/extension/icons/icon128.png +0 -0
- package/extension/icons/icon16.png +0 -0
- package/extension/icons/icon32.png +0 -0
- package/extension/icons/icon48.png +0 -0
- package/extension/logo.svg +0 -7
- package/extension/manifest.json +0 -47
- package/extension/sidepanel.css +0 -2
- package/extension/sidepanel.html +0 -138
- package/extension/sidepanel.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,207 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0 — the connection fix and chat (draft until the store publishes it)
|
|
4
|
+
|
|
5
|
+
Compared with the last public release (0.7.0). Only finished, tested work is listed. Everything is free during early
|
|
6
|
+
access; nothing that keeps you safe (approvals, hand-off, Stop) will ever be paid.
|
|
7
|
+
|
|
8
|
+
**It connects, and stays connected**
|
|
9
|
+
- **The side panel no longer sticks on "Connecting…".** If the connection came up before the panel started listening,
|
|
10
|
+
0.7.0 could show "Connecting…" forever while everything underneath worked. The panel now always picks it up.
|
|
11
|
+
- **The bridge comes back by itself after the extension reloads or updates.** Chrome updating BrowserZap no longer
|
|
12
|
+
leaves it waiting until your agent's next call or a manual `browserzap --bridge`.
|
|
13
|
+
- **Profile names stay put.** An unnamed profile keeps its number ("Profile 1") across reconnects and restarts, and
|
|
14
|
+
renaming one profile never changes another.
|
|
15
|
+
|
|
16
|
+
**Chat with your agent in the side panel**
|
|
17
|
+
- **Type to your agent in any tab's panel**, or point at elements and ask about them in the same message.
|
|
18
|
+
- **Your agent can listen** (`feedback_wait`): ask it to "listen to me in BrowserZap" and it answers as soon as you
|
|
19
|
+
write; the panel shows when it is listening. It replies in the tab you wrote from (`chat_reply`).
|
|
20
|
+
- **Each message goes to the agent working in that tab**, never to another agent you have open.
|
|
21
|
+
- **Each tab group's panel shows its own conversation**, not everything the agent did elsewhere.
|
|
22
|
+
- **A message is never lost because the agent went away.** If the agent you wrote to has ended, the message is handed
|
|
23
|
+
to the next agent for that tab instead of sitting unread. The panel tells you which happened: "Sent to … — it reads
|
|
24
|
+
this on its next step", or "Saved. No agent is connected to this tab right now; the next one reads it."
|
|
25
|
+
- **You can see it working.** The panel shows a one-line status ("● Claude is working: Clicking “Submit”") while a
|
|
26
|
+
call is in flight, and flips to a reply in the same tab as soon as the agent answers.
|
|
27
|
+
- **The conversation stays with the tab.** Close the panel, switch tabs, or restart Chrome and the tab's chat is still
|
|
28
|
+
there, stored on your computer and compressed (Settings → Chat history: 7 days, 30 days, or off). Clear conversation
|
|
29
|
+
really clears it.
|
|
30
|
+
- **And only with that tab.** Close a tab and its chat goes with it; reopen the tab (Ctrl+Shift+T) or let Chrome
|
|
31
|
+
restore it and the chat comes back. A new tab on the same site starts a fresh conversation.
|
|
32
|
+
- **Answers arrive as soon as you send.** A listening agent is told the moment you press Send, instead of noticing on
|
|
33
|
+
its next check.
|
|
34
|
+
- **A calmer conversation.** Connection messages stay in the header, and a long run of agent steps folds to its last
|
|
35
|
+
two, with the earlier ones a click away.
|
|
36
|
+
|
|
37
|
+
**Free during early access**
|
|
38
|
+
- **No limit on saved workflows** (0.7.0 kept 10).
|
|
39
|
+
|
|
40
|
+
**Clearer approvals**
|
|
41
|
+
- **The approval card says who presses the button:** "Press Approve once here — the agent then presses the button
|
|
42
|
+
itself."
|
|
43
|
+
- **Picking a tab, radio button or option no longer asks for approval** because its label says "Approve" or "Delete";
|
|
44
|
+
buttons, links and consent checkboxes still do.
|
|
45
|
+
|
|
46
|
+
**Settings, redesigned**
|
|
47
|
+
- Clear sections for this browser (connection, version, the profile name agents see), the plan, help links, and the
|
|
48
|
+
advanced pairing options.
|
|
49
|
+
|
|
50
|
+
**Also in this release**
|
|
51
|
+
|
|
52
|
+
**Work with your agent in more than one tab**
|
|
53
|
+
- **Open BrowserZap on any tab and it joins your agent.** With one agent connected, opening the side panel on a tab
|
|
54
|
+
gives the agent that tab as a new workspace: its own Chrome tab group labelled "<agent> · <site>", up to four per
|
|
55
|
+
agent. The agent is told and switches to it when it needs it; nothing moves under it.
|
|
56
|
+
- **Several agents side by side.** Run two agents (two Claude Code or Codex windows) and each keeps to its own tab
|
|
57
|
+
groups. When you open the panel on a new tab, it asks which agent the tab is for. One agent can never act in
|
|
58
|
+
another's tabs.
|
|
59
|
+
- **Your tabs stay yours.** Tabs you bring in from the panel are never closed or trimmed by the agent, and closing a
|
|
60
|
+
tab's panel hands that tab back as it is.
|
|
61
|
+
- **No more duplicate tabs after a restart.** When Chrome restarts BrowserZap's background service (after a while
|
|
62
|
+
idle, or when the extension updates), your agent takes back its own tab and group instead of opening new ones.
|
|
63
|
+
|
|
64
|
+
**Clearer on the page**
|
|
65
|
+
- **The approval card never covers a form field.** Approve once / Deny sits beside or below the button it asks
|
|
66
|
+
about, on the button's row, clear of every input.
|
|
67
|
+
- **A new agent cursor:** a gold arrow (Lucide's mouse pointer). While the agent types, the arrow steps aside and the
|
|
68
|
+
field's own blinking caret shows where the text goes, with the field's name beside it — never the value.
|
|
69
|
+
- **Panels on other tabs say where your agent is** ("working in another tab", with Show), and every tab whose panel
|
|
70
|
+
is open is marked **ON** in the toolbar.
|
|
71
|
+
- **Two copies of BrowserZap in one profile are called out** (for example the store version and a developer build),
|
|
72
|
+
with which one to turn off. Unnamed Chrome profiles get distinct names.
|
|
73
|
+
- First visit explains Chrome's "BrowserZap started debugging this browser" bar, and that pressing Cancel stops the
|
|
74
|
+
agent. The status pills in Workflows are easier to read (higher contrast), and the panel uses Lucide icons.
|
|
75
|
+
|
|
76
|
+
**More accurate results**
|
|
77
|
+
- A click that submits a form now reports a navigation that happens a moment later, instead of "no change".
|
|
78
|
+
- Chrome's debugging bar no longer flickers mid-task (BrowserZap lets go after 5 idle minutes, and at once when the
|
|
79
|
+
agent finishes).
|
|
80
|
+
|
|
81
|
+
**For developers**
|
|
82
|
+
- `browserzap setup` names the store extension id it registered in store-only mode.
|
|
83
|
+
- `npm run release:changes`, `release:public` and `release:internal` (docs/RELEASE_CHECKLIST.md).
|
|
84
|
+
|
|
85
|
+
## 0.8.0 (internal)
|
|
86
|
+
|
|
87
|
+
**Internal only.** Built and installed from the checkout for the owner's own use (`browserzap-0.8.0.tgz`, packed
|
|
88
|
+
locally); never published to npm, the Chrome Web Store or the website. Branch `integration/0.8` → `release/0.8`.
|
|
89
|
+
Full browser suite and unit tests: see docs/releases/0.8.0-internal.md.
|
|
90
|
+
|
|
91
|
+
### Tabs, workspaces and several agents
|
|
92
|
+
- **Workspaces.** Opening the side panel on a tab with one agent connected adds the tab to that session as a new
|
|
93
|
+
workspace group "<agent> · <site>" (≤ 4 groups per session, `MAX_WORKSPACES_PER_SESSION`). Panels already open when
|
|
94
|
+
an agent connects join it too. The agent gets a note on its next call; `browser_list_tabs` returns
|
|
95
|
+
`role: "workspace"` and `workspace: "<label>"` (read back from Chrome after a restart). Workspace tabs are the
|
|
96
|
+
person's (`sharedTabs`): never trimmed, kept and ungrouped when the session ends, released when their panel closes.
|
|
97
|
+
- **Several agents.** With more than one agent connected the panel shows a picker (`join_tab`); nothing joins on its
|
|
98
|
+
own. `tabBelongs` checks the session's group and its workspace groups; another session's tab is
|
|
99
|
+
`PERMISSION_REQUIRED`. Proven with two real MCP clients interleaving navigate, fill, chat, approval and click (B-04,
|
|
100
|
+
`concurrent-agents.e2e.mjs`).
|
|
101
|
+
- **"Work here".** Sharing a tab when exactly one agent is connected moves that agent there (`giveTabToAgent`): the
|
|
102
|
+
tab joins its group, becomes its session tab, and the next page action is stopped once with the reason
|
|
103
|
+
(`tabNotice`, D-21). Panels on tabs without an agent name the agent busy elsewhere, with Show; the header says
|
|
104
|
+
"N agents in another tab".
|
|
105
|
+
- **Reclaim after a restart.** The saved session map is merged, not overwritten (`persistSessions`), so the first
|
|
106
|
+
session to come back after a service-worker restart no longer erases the others; an entry is removed only when its
|
|
107
|
+
session ends (`forgetSavedSession`). A debugger attachment left by the previous worker is taken back
|
|
108
|
+
(`reclaimOwnAttachment`: only our own attachment can be detached) instead of failing with "Another debugger is
|
|
109
|
+
already attached".
|
|
110
|
+
- **The bridge comes back by itself (B-10).** After an extension reload, a paired extension now asks the native
|
|
111
|
+
helper to start the bridge when its connection fails, instead of waiting for an agent or a manual
|
|
112
|
+
`browserzap --bridge`. The helper runs ensure-bridge, the extension reconnects, and it stops asking while the
|
|
113
|
+
connection is healthy.
|
|
114
|
+
- **Debugger hold on the action's tab.** The no-detach-mid-action hold now covers the tab an action actually runs on
|
|
115
|
+
(a session's first tab, or one switched to mid-call), not only the session tab at the start of the call.
|
|
116
|
+
|
|
117
|
+
### Side panel and page
|
|
118
|
+
- **Chat (internal, Pro).** The message box is on in internal builds (`src/sidepanel/features.ts`); a message is a
|
|
119
|
+
feedback batch with `kind: "message"`; every tool result reminds the agent until `feedback_get`; `chat_reply`
|
|
120
|
+
answers in the panel (offered with `BROWSERZAP_EXPERIMENTAL=chat`). Before any public release it must be off or
|
|
121
|
+
gated by the licence.
|
|
122
|
+
- **Approval card placement** (B-01): every candidate spot is first moved on screen, then judged by what it covers
|
|
123
|
+
(other controls and the marked element itself); if none is clear it slides along the same rows until it is; on a
|
|
124
|
+
page with no clear spot it takes the one that covers least. Rules unchanged: trusted clicks only, `tabIndex = -1`,
|
|
125
|
+
out of the agent's reach.
|
|
126
|
+
- **Cursor:** Lucide `mouse-pointer-2`, gold (`#f5b335`) with a dark outline. The drawn I-beam caret is removed: a
|
|
127
|
+
typing step hides the arrow (decided by the step, not by focus) and shows only the field's name.
|
|
128
|
+
- **Icons:** `lucide-preact` (ISC) for the panel's settings, send, pin, copy and close; brand marks unchanged.
|
|
129
|
+
- **ON badge** on every tab whose panel is open (B-03); duplicate-build warning and never-reused profile numbers
|
|
130
|
+
(B-05); the debugging bar explained on first visit (B-08); darker text on the status pills (axe contrast).
|
|
131
|
+
- The panel subscribes to state in a layout effect and connects its tab port at load, so a panel that has not painted
|
|
132
|
+
yet still receives updates and hands its tab back when closed.
|
|
133
|
+
- Late navigation after a click that started a request is reported (B-02, `NAVIGATION_FOLLOW_MS`).
|
|
134
|
+
|
|
135
|
+
### Tests and release tooling
|
|
136
|
+
- **Browser suite: ~15 → ~12 minutes** for the full lane: compile-time E2E build (`build:e2e` → `extension-e2e/`,
|
|
137
|
+
short `DEBUGGER_IDLE_MS` / `TAB_TRIM_IDLE_MS` / `SESSION_GRACE_MS`; production values pinned by the contract test),
|
|
138
|
+
`expect` on clicks, `until()` instead of fixed sleeps, grouped files, lanes `test:e2e:fast`, `test:e2e`,
|
|
139
|
+
`test:e2e:real-timers`. The debugger idle case dropped from 5 min to ~5 s.
|
|
140
|
+
- **New checks:** console/exception guard on BrowserZap's own pages and worker, panel layout at 320/420/600 px,
|
|
141
|
+
axe-core accessibility, keyboard flow, service-worker suspension, orphan-process and redaction scans, failure
|
|
142
|
+
bundles in `artifacts/e2e-failures/`, JSON timings.
|
|
143
|
+
- **Build guard:** the E2E build compiles into `dist/chrome-e2e` with a marker the store packager refuses.
|
|
144
|
+
- **Fixed traps:** the harness no longer attaches to web pages (it made every tab look "debugged" and held up new
|
|
145
|
+
tabs); `test:e2e` always runs every test — re-running only failures is `test:e2e:rerun-failed`, never a release
|
|
146
|
+
lane.
|
|
147
|
+
- Store records per release (`docs/store/`, browser view `docs/store/index.html`) and the public/internal release
|
|
148
|
+
checklist (`docs/RELEASE_CHECKLIST.md`) — shipped with 0.7.0's records.
|
|
149
|
+
|
|
150
|
+
### Cleanup
|
|
151
|
+
- 13 finished worktrees and 46 merged local branches removed; 33 merged remote branches deleted (backup bundle first);
|
|
152
|
+
GitHub deletes head branches on merge. Finished plans and reports moved to `docs/archive/` (links updated).
|
|
153
|
+
Branch, worktree and push-batching rules in `docs/DEVELOPMENT_WORKFLOW.md`. Architecture plan:
|
|
154
|
+
`docs/design/FEATURE_MODULES.md`.
|
|
155
|
+
|
|
156
|
+
## 0.7.0 — public launch
|
|
157
|
+
|
|
158
|
+
BrowserZap is public: free, and installed from the Chrome Web Store.
|
|
159
|
+
|
|
160
|
+
- **The extension comes from the Chrome Web Store:**
|
|
161
|
+
<https://chromewebstore.google.com/detail/bbnmhaonicbmljhbahimpgfafbjoijpe>. Chrome keeps it updated. There is no
|
|
162
|
+
folder to load and no Developer mode.
|
|
163
|
+
- **The npm package no longer includes the extension.** `npm install -g browserzap` brings the bridge, the native
|
|
164
|
+
messaging helper and the MCP server — not `extension/`. `browserzap setup` prints the store link when the extension
|
|
165
|
+
is missing, and `--extension` (a developer option) now says so instead of installing nothing.
|
|
166
|
+
- **The helper accepts only the store extension by default.** `browserzap setup --dev` adds a developer's unpacked
|
|
167
|
+
build to the allowed ids and remembers the choice; a plain `setup` goes back to store-only and says so.
|
|
168
|
+
- **`browserzap doctor` works on an npm install** with no bundled extension: it names the store id and passes.
|
|
169
|
+
- **The bridge knows which extension it is talking to.** `hello` carries the extension's version, `browser_status`
|
|
170
|
+
shows it, and a store build older than the bridge gets a notice — never a refused connection. Chrome updates the
|
|
171
|
+
extension on its own; to update now, open `chrome://extensions` and press **Update**.
|
|
172
|
+
- **A new side panel, built to be understood on first sight** (Preact, still compiled locally with Tailwind):
|
|
173
|
+
- **Chat** shows what the agent does in this tab as a conversation, and a first-visit guide in three steps with
|
|
174
|
+
prompts to copy. **Workflows** holds saved tasks. The Comment tab is gone: **Point at page** at the bottom of the
|
|
175
|
+
panel does the same.
|
|
176
|
+
- **Notes reach the agent sooner.** Every tool result now tells the agent that notes are waiting until it calls
|
|
177
|
+
`feedback_get` (it used to be `browser_status` only).
|
|
178
|
+
- **Take over / Hand back** replaces the Collab/AI/User switch. Approvals and "Your turn" hand-offs sit at the
|
|
179
|
+
bottom, always in reach; a decision waiting in another tab says so with a **Show** button.
|
|
180
|
+
- A half-typed hand-off note is no longer wiped while the agent works, and the conversation stops jumping to the
|
|
181
|
+
bottom while you read further up.
|
|
182
|
+
- **Give your agent the tab you are on.** **Let the agent use this tab** in that tab's panel: the agent's next request
|
|
183
|
+
works there instead of opening a new tab, and an agent already working sees it in `browser_list_tabs` (role
|
|
184
|
+
`shared-available`) and can `browser_switch_tab` to it. An agent never takes a tab nobody shared. A shared tab stays
|
|
185
|
+
yours: when the session ends it is kept, not closed.
|
|
186
|
+
- **Chrome's "BrowserZap started debugging this browser" bar no longer flickers between steps.** BrowserZap now lets go
|
|
187
|
+
of a tab after 5 minutes without an agent action (was 60 s), and still at once when the session ends, when you take
|
|
188
|
+
over, hand off or close the panel.
|
|
189
|
+
- **The panel says "Connecting…" while Chrome wakes BrowserZap up**, instead of "offline".
|
|
190
|
+
- **The side panel belongs to one tab.** It opens where you click the toolbar icon (and is available on the agent's
|
|
191
|
+
tabs) and hides when you switch to another tab. The toolbar badge reads **ON** only on tabs BrowserZap controls, or
|
|
192
|
+
the number of decisions waiting there.
|
|
193
|
+
- **Closing the side panel hands the tab back.** Comment mode ends (it used to come back on every reload), a recording
|
|
194
|
+
is dropped, and an agent working there lets go of the tab: it leaves the group, stays open as it is, its overlays go
|
|
195
|
+
and the debugger detaches. The agent's next page action is told the person took the tab back.
|
|
196
|
+
- **An existing upload is detected** (#65): `file_upload` reports the file already on the input instead of asking for
|
|
197
|
+
a second approval, and tells the agent to ask before replacing it.
|
|
198
|
+
- **Comment screenshots show context** (#66): each element crop now includes the surrounding page instead of a tight
|
|
199
|
+
cut-out.
|
|
200
|
+
- No new tools and no new permission; the protocol stays 4, and approvals, hand-off and Stop stay free.
|
|
201
|
+
|
|
3
202
|
## 0.6.1 (2026-10-30)
|
|
4
203
|
|
|
5
|
-
The changes from three real-Chrome runs in the owner's own browser (docs/REVIEW_LATER.md, K-7…K-10). Checked in the
|
|
204
|
+
The changes from three real-Chrome runs in the owner's own browser (docs/archive/REVIEW_LATER.md, K-7…K-10). Checked in the
|
|
6
205
|
owner's Chrome: `npm run check:chrome` 9/9, approval through the page card, the test tab closed at session end.
|
|
7
206
|
|
|
8
207
|
- **No more tabs left behind.** The tab group is the contract: while the agent is connected its tabs stay open in the
|
|
@@ -58,7 +257,7 @@ A replay now waits for what the step is actually blocked on, and retries that st
|
|
|
58
257
|
|
|
59
258
|
## 0.5.5 (2026-10-30)
|
|
60
259
|
|
|
61
|
-
Comment mode, debugging tools, files, Edge and WSL, a much better doctor, and the Chrome Web Store build. Known items to review are listed in docs/REVIEW_LATER.md (upload approval visibility, a file the person picks themselves, a download re-test, wider Comment screenshots, a calmer side panel).
|
|
260
|
+
Comment mode, debugging tools, files, Edge and WSL, a much better doctor, and the Chrome Web Store build. Known items to review are listed in docs/archive/REVIEW_LATER.md (upload approval visibility, a file the person picks themselves, a download re-test, wider Comment screenshots, a calmer side panel).
|
|
62
261
|
|
|
63
262
|
- No more stuck file dialogs: when the agent clicks a page's "Choose file" control, no Windows file picker opens; the result says the page asked for a file and to use `file_upload`. Your own clicks open the picker as usual. If Chrome is set to ask where to save each download, `browserzap doctor` and `browser_downloads` say so and how to turn it off (an extension cannot skip that dialog).
|
|
64
263
|
- Messages for people who installed from npm: the side panel, the extension and the agent no longer point to source-only commands (`npm run health`, `npm run bridge:restart`, …) but to `browserzap doctor`, `browserzap restart-bridge`, `browserzap --print-token`. When a bridge from another install holds the port, the side panel now says so and shows the fix instead of staying grey.
|
package/README.md
CHANGED
|
@@ -28,26 +28,30 @@ browser, no copied cookies and no new login: the agent works in your real tab, a
|
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
1. **Add the extension from the Chrome Web Store:**
|
|
32
|
+
<https://chromewebstore.google.com/detail/bbnmhaonicbmljhbahimpgfafbjoijpe>. Chrome keeps it updated for you.
|
|
33
|
+
|
|
34
|
+
2. **Install the companion program** (the bridge and the MCP server; it needs Node.js 22 or newer):
|
|
35
|
+
|
|
36
|
+
```cmd
|
|
37
|
+
npm install -g browserzap
|
|
38
|
+
```
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
3. **Run setup once:**
|
|
41
|
+
|
|
42
|
+
```cmd
|
|
43
|
+
browserzap setup
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`browserzap setup` does two things, and is safe to run again:
|
|
37
47
|
|
|
38
48
|
1. Registers a small helper with Chrome and Edge for your Windows user only (no administrator rights), so the
|
|
39
|
-
extension connects by itself. There is no token to copy.
|
|
40
|
-
2.
|
|
41
|
-
3. Finds Claude Code, Codex CLI and Cursor, shows the exact entry it would add for BrowserZap, and adds it only after
|
|
49
|
+
extension connects by itself and can start the companion program. There is no token to copy.
|
|
50
|
+
2. Finds Claude Code, Codex CLI and Cursor, shows the exact entry it would add for BrowserZap, and adds it only after
|
|
42
51
|
you answer `y`.
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- **From the Chrome Web Store** (in review; this link works once it is published):
|
|
47
|
-
<https://chromewebstore.google.com/detail/bbnmhaonicbmljhbahimpgfafbjoijpe>. Chrome keeps it updated.
|
|
48
|
-
- **Until then, load it unpacked** (Chrome does not allow this step to be automated):
|
|
49
|
-
1. Open `chrome://extensions` and turn on **Developer mode**.
|
|
50
|
-
2. Click **Load unpacked** and choose the folder `setup` printed.
|
|
53
|
+
The npm package ships the bridge, the native helper and the MCP server — **not** the extension. If the extension is
|
|
54
|
+
not installed yet, `setup` prints the store link.
|
|
51
55
|
|
|
52
56
|
Click the BrowserZap icon to open the side panel. It turns green when it is connected. Check everything with:
|
|
53
57
|
|
|
@@ -58,6 +62,13 @@ browserzap doctor
|
|
|
58
62
|
Using Claude Code inside WSL? BrowserZap stays on Windows; in WSL run
|
|
59
63
|
`claude mcp add browserzap -- cmd.exe /c browserzap` (details: <https://browserzap.com/docs/platforms>).
|
|
60
64
|
|
|
65
|
+
### Developers
|
|
66
|
+
|
|
67
|
+
From a source checkout, `npm run build` still writes `extension/`, which you can load with **Load unpacked** in
|
|
68
|
+
`chrome://extensions` (turn on **Developer mode**). Run `browserzap setup --dev` so the helper accepts that build;
|
|
69
|
+
`setup` without `--dev` goes back to the store extension only. From a checkout without a global install, the same
|
|
70
|
+
command is `node bridge-server/index.js setup --dev`.
|
|
71
|
+
|
|
61
72
|
## Use it
|
|
62
73
|
|
|
63
74
|
Restart your MCP client and ask for something in the browser, for example: *"Open example.com and tell me what the
|
|
@@ -88,7 +99,7 @@ Start with `browserzap doctor`: every failed line says what to do.
|
|
|
88
99
|
| Doctor: *a bridge with a different pairing secret holds 127.0.0.1:9334* | `browserzap restart-bridge`, then **Reconnect** in the side panel |
|
|
89
100
|
| Doctor: *Launcher finds Node and the helper* fails | Node moved (a version switch with fnm, Volta or nvm): run `browserzap setup` again |
|
|
90
101
|
| Doctor: *Not blocked by Chrome policy* fails | Your computer is managed; ask IT to allow the helper `com.browserzap.bridge` and the extension |
|
|
91
|
-
| Chrome says *Disable developer mode extensions* on start-up |
|
|
102
|
+
| Chrome says *Disable developer mode extensions* on start-up | Only with a developer's unpacked copy: choose **Keep**. The Chrome Web Store install never shows it |
|
|
92
103
|
| A bar says *"BrowserZap" started debugging this browser* | Expected while an agent can act; it goes away when the agent ends or after a minute idle |
|
|
93
104
|
| Your agent does not list BrowserZap's tools | Restart the agent app after `browserzap setup`. To add it by hand, `browserzap --help` prints the exact MCP configuration |
|
|
94
105
|
| A step stops with *"needs you"* | The page asked for a password, a code or an approval. Do it, press **Done**, and the agent continues |
|
|
@@ -104,7 +115,7 @@ More: <https://browserzap.com/docs/troubleshooting>.
|
|
|
104
115
|
| `browserzap doctor` | Checks the helper registration, the launcher, Chrome policy, the extension id and the connection |
|
|
105
116
|
| `browserzap restart-bridge` | Replaces a bridge that will not pair (another install's secret or an old version) |
|
|
106
117
|
| `browserzap run <workflow> --params rows.csv` | Runs a saved workflow without an agent (one row on the free plan) |
|
|
107
|
-
| `browserzap uninstall` | Removes the helper registration and
|
|
118
|
+
| `browserzap uninstall` | Removes the helper registration (and a developer's unpacked copy); keeps your data |
|
|
108
119
|
| `browserzap uninstall --purge` | Also removes your BrowserZap data folder (cannot be undone) |
|
|
109
120
|
|
|
110
121
|
Environment variables (allowed sites, profile, upload folder, retention, …): <https://browserzap.com/docs/configuration>.
|
|
@@ -116,8 +127,9 @@ npm install -g browserzap@latest
|
|
|
116
127
|
browserzap setup
|
|
117
128
|
```
|
|
118
129
|
|
|
119
|
-
|
|
120
|
-
|
|
130
|
+
Chrome updates the extension from the Chrome Web Store by itself. Your workflows, run reports and settings are kept.
|
|
131
|
+
If the extension is older than the companion program, the agent's status result says so: Chrome retries on its own, or
|
|
132
|
+
open `chrome://extensions` and press **Update**.
|
|
121
133
|
|
|
122
134
|
## Free and Pro
|
|
123
135
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -78,6 +78,8 @@ No copyleft, source-available-restricted or non-commercial licences are present
|
|
|
78
78
|
| Package | Licence | Purpose |
|
|
79
79
|
|---|---|---|
|
|
80
80
|
| `ws` | MIT | WebSocket transport for the local bridge |
|
|
81
|
+
| `preact` | MIT | Side-panel UI, bundled into the extension's `sidepanel.js` (Copyright (c) 2015-present Jason Miller) |
|
|
82
|
+
| `lucide-preact` | ISC | Side-panel icons, bundled into `sidepanel.js`; the page cursor draws Lucide's `mouse-pointer-2` path (Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT); all other copyright (c) for Lucide are held by Lucide Contributors 2022) |
|
|
81
83
|
|
|
82
84
|
### Build-time only (not redistributed)
|
|
83
85
|
|
|
@@ -85,9 +87,8 @@ No copyleft, source-available-restricted or non-commercial licences are present
|
|
|
85
87
|
`copy-webpack-plugin`, `@types/chrome` and their transitive dependencies — including all
|
|
86
88
|
packages listed above as Apache-2.0, BSD and CC-BY-4.0.
|
|
87
89
|
|
|
88
|
-
The extension bundle emitted by webpack contains first-party source
|
|
89
|
-
|
|
90
|
-
`./src/...`).
|
|
90
|
+
The extension bundle emitted by webpack contains first-party source, the webpack runtime and,
|
|
91
|
+
since 0.7.0, `preact` in the side panel's `sidepanel.js` (MIT; listed above).
|
|
91
92
|
|
|
92
93
|
---
|
|
93
94
|
|
|
@@ -257,7 +257,7 @@ function createRunRegistry({ execute, onFinish = () => {}, now = Date.now }) {
|
|
|
257
257
|
/**
|
|
258
258
|
* The part of a finished batch an agent needs: counts and, per set that did not
|
|
259
259
|
* complete, where and why. Everything else is in the report. Kept well under
|
|
260
|
-
* 700 bytes per set (docs/NEXT_RELEASE_SCOPE.md P0-5).
|
|
260
|
+
* 700 bytes per set (docs/archive/NEXT_RELEASE_SCOPE.md P0-5).
|
|
261
261
|
*/
|
|
262
262
|
function compactBatch(result) {
|
|
263
263
|
const ev = result?.evidence ?? {};
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
* BrowserZap — plan and entitlements (docs/ADR/ADR-006-free-pro-boundary.md).
|
|
3
3
|
*
|
|
4
4
|
* The free core is everything that keeps an agent safe and useful on its own:
|
|
5
|
-
* every browser tool, approvals, handoff, honest errors and
|
|
6
|
-
* Pro adds workflow history, bulk runs
|
|
7
|
-
* FREE_LIMITS.workflows saved workflows. Nothing here ever gates a safety check.
|
|
5
|
+
* every browser tool, approvals, handoff, honest errors and workflows.
|
|
6
|
+
* Pro adds workflow history, bulk runs and run reports. Nothing here ever gates a safety check.
|
|
8
7
|
*
|
|
9
8
|
* A licence is a signed token issued by the licence service after payment:
|
|
10
9
|
*
|
|
@@ -36,15 +35,18 @@ const LICENSE_FILENAME = 'license';
|
|
|
36
35
|
const GRACE_DAYS = 14;
|
|
37
36
|
const DAY_S = 24 * 60 * 60;
|
|
38
37
|
|
|
39
|
-
/**
|
|
40
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Limits that apply without a licence. Early access (owner decision 2026-11-03, docs/DECISIONS.md D-0.8-1): no
|
|
40
|
+
* limit on saved workflows; the site promises every shipped feature free. A cap returns only with notice on the site.
|
|
41
|
+
*/
|
|
42
|
+
const FREE_LIMITS = Object.freeze({});
|
|
41
43
|
|
|
42
44
|
/** Every Pro feature, with the text shown when it is missing. */
|
|
43
45
|
const PRO_FEATURES = Object.freeze({
|
|
44
46
|
'workflow.history': 'keeps every saved version of a workflow and can run or restore an older one',
|
|
45
47
|
'workflow.bulk': 'runs one workflow over many parameter sets in a single call',
|
|
46
48
|
'workflow.reports': 'keeps a local report of every workflow run',
|
|
47
|
-
'workflow.unlimited':
|
|
49
|
+
'workflow.unlimited': 'saves any number of workflows',
|
|
48
50
|
});
|
|
49
51
|
|
|
50
52
|
const PLAN_FEATURES = Object.freeze({
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* The Chrome Web Store signs its own build and does not accept a manifest
|
|
11
11
|
* `key`, so the store build may get a different id. Fill in
|
|
12
12
|
* STORE_EXTENSION_ID from the developer dashboard after the first upload; the
|
|
13
|
-
* native host then lets both builds in
|
|
13
|
+
* native host then lets both builds in, once `setup --dev` allows the unpacked
|
|
14
|
+
* one (docs/RELEASE.md §3b).
|
|
14
15
|
*
|
|
15
16
|
* Everything that has to name the extension — the native messaging host
|
|
16
17
|
* manifest's allowed_origins, `browserzap doctor`, the tests — reads the id
|
|
@@ -18,11 +19,20 @@
|
|
|
18
19
|
* changed key fails `doctor` and the tests instead of silently breaking native
|
|
19
20
|
* messaging.
|
|
20
21
|
*
|
|
22
|
+
* The store build is the only build a user has (D3), so the store id is the
|
|
23
|
+
* only one allowed by default. `browserzap setup --dev` saves
|
|
24
|
+
* `{ "allowDevExtension": true }` in the config dir (next to the pairing
|
|
25
|
+
* secret, user-only permissions) and the unpacked id is allowed on top of it.
|
|
26
|
+
* Chrome starts the native host itself, so an env var in the user's shell can
|
|
27
|
+
* never carry that choice (F2): the file can.
|
|
28
|
+
*
|
|
21
29
|
* Derived from the manifest key in src/manifest.json. Chrome computes:
|
|
22
30
|
* id = SHA-256(SPKI DER public key), first 16 bytes, each hex nibble 0-f → a-p
|
|
23
31
|
*/
|
|
24
32
|
|
|
25
33
|
const crypto = require('crypto');
|
|
34
|
+
const fs = require('fs');
|
|
35
|
+
const path = require('path');
|
|
26
36
|
|
|
27
37
|
/** chrome-extension://gienkaoaimdjmcjdejjanmbkpfakmkno/ */
|
|
28
38
|
const EXTENSION_ID = 'gienkaoaimdjmcjdejjanmbkpfakmkno';
|
|
@@ -36,6 +46,9 @@ const ALLOWED_EXTENSION_IDS = Object.freeze([EXTENSION_ID, STORE_EXTENSION_ID].f
|
|
|
36
46
|
/** Name Chrome uses for the native messaging host; also the registry key's leaf. */
|
|
37
47
|
const HOST_NAME = 'com.browserzap.bridge';
|
|
38
48
|
|
|
49
|
+
/** Written by `browserzap setup --dev` in the config dir; its absence means store only. */
|
|
50
|
+
const DEV_FLAG_FILENAME = 'allow-dev-extension';
|
|
51
|
+
|
|
39
52
|
function extensionOrigin(id = EXTENSION_ID) {
|
|
40
53
|
return `chrome-extension://${id}/`;
|
|
41
54
|
}
|
|
@@ -45,6 +58,52 @@ function allowedOrigins(ids = ALLOWED_EXTENSION_IDS) {
|
|
|
45
58
|
return ids.map((id) => extensionOrigin(id));
|
|
46
59
|
}
|
|
47
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Whether the saved dev flag in `dir` allows the unpacked developer build.
|
|
63
|
+
*
|
|
64
|
+
* Fail closed: a missing, unreadable or malformed file means store only (D4).
|
|
65
|
+
*/
|
|
66
|
+
function devExtensionAllowed(dir) {
|
|
67
|
+
if (typeof dir !== 'string' || !dir) return false;
|
|
68
|
+
try {
|
|
69
|
+
const saved = JSON.parse(fs.readFileSync(path.join(dir, DEV_FLAG_FILENAME), 'utf8'));
|
|
70
|
+
return saved?.allowDevExtension === true;
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Save (or clear) the dev flag. `setup` calls this before it writes the host
|
|
78
|
+
* manifest, so the manifest and the host's own check read the same answer.
|
|
79
|
+
*/
|
|
80
|
+
function setDevExtensionAllowed(dir, allowed) {
|
|
81
|
+
if (typeof dir !== 'string' || !dir) return false;
|
|
82
|
+
const file = path.join(dir, DEV_FLAG_FILENAME);
|
|
83
|
+
if (!allowed) {
|
|
84
|
+
try { fs.rmSync(file, { force: true }); } catch { /* already gone */ }
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
88
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
89
|
+
fs.writeFileSync(tmp, '{"allowDevExtension":true}\n', { mode: 0o600 });
|
|
90
|
+
fs.renameSync(tmp, file);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Every extension id the native host may let in: the store id, plus the
|
|
96
|
+
* unpacked id when `setup --dev` saved the flag.
|
|
97
|
+
*
|
|
98
|
+
* `dir` defaults to the config dir, resolved lazily so importing this module
|
|
99
|
+
* never reads the filesystem or triggers the legacy-folder check.
|
|
100
|
+
*/
|
|
101
|
+
function allowedExtensionIds({ dir } = {}) {
|
|
102
|
+
const configDir = dir === undefined ? require('./secret').configDir() : dir;
|
|
103
|
+
const ids = devExtensionAllowed(configDir) ? [EXTENSION_ID, STORE_EXTENSION_ID] : [STORE_EXTENSION_ID];
|
|
104
|
+
return ids.filter(Boolean);
|
|
105
|
+
}
|
|
106
|
+
|
|
48
107
|
/**
|
|
49
108
|
* Chrome's extension id for a manifest `key` value (base64 SPKI DER).
|
|
50
109
|
* Returns null when the key is missing or is not a valid public key.
|
|
@@ -72,7 +131,11 @@ module.exports = {
|
|
|
72
131
|
STORE_EXTENSION_ID,
|
|
73
132
|
ALLOWED_EXTENSION_IDS,
|
|
74
133
|
HOST_NAME,
|
|
134
|
+
DEV_FLAG_FILENAME,
|
|
75
135
|
extensionOrigin,
|
|
76
136
|
allowedOrigins,
|
|
137
|
+
devExtensionAllowed,
|
|
138
|
+
setDevExtensionAllowed,
|
|
139
|
+
allowedExtensionIds,
|
|
77
140
|
extensionIdFromKey,
|
|
78
141
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* The extension version the bridge expects (WP5, F4).
|
|
4
|
+
*
|
|
5
|
+
* The Chrome Web Store ships the extension and updates it on its own schedule,
|
|
6
|
+
* so after the 0.7.0 launch the store build will often lag the npm bridge by a
|
|
7
|
+
* review cycle. The extension's `hello` carries `extensionVersion` (an additive
|
|
8
|
+
* field; the protocol stays 4), the bridge stores it per profile, and
|
|
9
|
+
* `browser_status` says plainly when the connected build is older than this
|
|
10
|
+
* bridge expects.
|
|
11
|
+
*
|
|
12
|
+
* Nothing here ever refuses a connection or a call: a missing version means an
|
|
13
|
+
* older build (≤ 0.6.1), which is exactly the case the notice is for.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The oldest extension build this bridge describes as current. */
|
|
17
|
+
const MIN_EXTENSION_VERSION = '0.7.0';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One numeric part per dot-separated segment. Anything that is not a version at
|
|
21
|
+
* all counts as 0, so a short, long or odd string still compares instead of
|
|
22
|
+
* throwing.
|
|
23
|
+
*/
|
|
24
|
+
function versionParts(version) {
|
|
25
|
+
let text = '';
|
|
26
|
+
if (typeof version === 'string') text = version.trim();
|
|
27
|
+
else if (typeof version === 'number' && Number.isFinite(version)) text = String(version);
|
|
28
|
+
if (!text) return [0];
|
|
29
|
+
return text.split('.').map((segment) => {
|
|
30
|
+
const match = /^\d+/.exec(segment.trim());
|
|
31
|
+
return match ? Number(match[0]) : 0;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Numeric dot comparison: 0.7.0 > 0.6.1, 0.7 > 0.7.0, 0.7.0.1 > 0.7.0.
|
|
37
|
+
* Returns -1 when `a` is older, 0 when equal, 1 when newer.
|
|
38
|
+
*/
|
|
39
|
+
function compareVersions(a, b) {
|
|
40
|
+
const left = versionParts(a);
|
|
41
|
+
const right = versionParts(b);
|
|
42
|
+
const length = Math.max(left.length, right.length);
|
|
43
|
+
for (let i = 0; i < length; i++) {
|
|
44
|
+
const x = left[i] ?? 0;
|
|
45
|
+
const y = right[i] ?? 0;
|
|
46
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* True only for a real version string that is older than `minimum`. A missing
|
|
53
|
+
* or non-string version answers false: "unknown" is not the same as "old", and
|
|
54
|
+
* the caller decides what to say about it.
|
|
55
|
+
*/
|
|
56
|
+
function isOlderThan(version, minimum) {
|
|
57
|
+
if (typeof version !== 'string' || !version.trim()) return false;
|
|
58
|
+
return compareVersions(version, minimum) < 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = {
|
|
62
|
+
MIN_EXTENSION_VERSION,
|
|
63
|
+
compareVersions,
|
|
64
|
+
isOlderThan,
|
|
65
|
+
};
|