chromeflow 0.1.54 → 0.1.56
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/CLAUDE.md +26 -0
- package/README.md +20 -0
- package/dist/setup.js +10 -3
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -238,4 +238,30 @@ document.body.style.zoom = '1';
|
|
|
238
238
|
1. Retry the exact same `execute_script` call
|
|
239
239
|
2. If still failing, use `find_and_highlight` to show the user a download button to click manually
|
|
240
240
|
|
|
241
|
+
**Shadow DOM `[role=radio]` / custom radios silently no-op**: On sites like Outlier,
|
|
242
|
+
`element.click()` on a shadow-DOM radio often doesn't flip `aria-checked`. Two things
|
|
243
|
+
must be true: (a) the element must be scrolled into view FIRST (`scrollIntoView({block:'center'})`),
|
|
244
|
+
and (b) the full pointer-event chain must fire — not just `click()`:
|
|
245
|
+
```js
|
|
246
|
+
['pointerdown','mousedown','pointerup','mouseup','click'].forEach(t =>
|
|
247
|
+
el.dispatchEvent(new MouseEvent(t, {bubbles: true, cancelable: true}))
|
|
248
|
+
);
|
|
249
|
+
```
|
|
250
|
+
After scroll, re-query the radio list — its length may change as more content becomes
|
|
251
|
+
visible. Then verify `aria-checked === "true"` before moving on.
|
|
252
|
+
|
|
253
|
+
**Visibility-detection overlays** (e.g. Multimango's "Content Hidden" black overlay):
|
|
254
|
+
Some sites render a full-screen overlay when the tab loses focus, triggered by
|
|
255
|
+
`document.visibilityState` / `document.hidden`. Chromeflow tab-switching triggers it.
|
|
256
|
+
Workaround — remove the overlay and patch the APIs:
|
|
257
|
+
```js
|
|
258
|
+
document.querySelectorAll('[style*="z-index: 99999"]').forEach(el => el.remove());
|
|
259
|
+
Object.defineProperty(document, 'hidden', { get: () => false, configurable: true });
|
|
260
|
+
Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true });
|
|
261
|
+
['visibilitychange','blur'].forEach(t =>
|
|
262
|
+
document.addEventListener(t, e => e.stopImmediatePropagation(), true)
|
|
263
|
+
);
|
|
264
|
+
```
|
|
265
|
+
Re-apply after every navigation.
|
|
266
|
+
|
|
241
267
|
**Never use Bash to work around a stuck browser interaction.**
|
package/README.md
CHANGED
|
@@ -108,6 +108,26 @@ set_file_input("Upload", "/Users/you/Downloads/task.zip")
|
|
|
108
108
|
|
|
109
109
|
Click the Chromeflow extension icon and use **"Use this window for Claude"** to lock Claude's browser operations to a specific Chrome window. This lets you freely use other Chrome windows without Claude interfering.
|
|
110
110
|
|
|
111
|
+
### Running multiple Claude Code instances in parallel
|
|
112
|
+
|
|
113
|
+
Chromeflow supports up to 11 Claude Code sessions running in parallel, each automating a different Chrome window without touching the others.
|
|
114
|
+
|
|
115
|
+
**How it works:**
|
|
116
|
+
- Each CC session spawns its own Chromeflow MCP server, which auto-discovers a free port in the range `7878-7888` (first session gets 7878, second gets 7879, etc.).
|
|
117
|
+
- The Chrome extension maintains one WebSocket connection per port and tracks per-port window assignments.
|
|
118
|
+
- Every browser tool call is routed to the Chrome window assigned to the port the request came in on.
|
|
119
|
+
|
|
120
|
+
**Setup:**
|
|
121
|
+
1. Start your first Claude Code session as normal — its Chromeflow will claim port 7878.
|
|
122
|
+
2. Start a second CC session in another terminal — its Chromeflow auto-falls-back to 7879.
|
|
123
|
+
3. Click the Chromeflow extension icon. The popup now shows **one row per instance** (Port 7878, Port 7879, ...) each with a green dot when live.
|
|
124
|
+
4. In Chrome **window A**, open the popup and click **"Use this window"** next to Port 7878.
|
|
125
|
+
5. Switch to **window B**, open the popup, and click **"Use this window"** next to Port 7879.
|
|
126
|
+
|
|
127
|
+
That's it. Each CC session now drives its own Chrome window — you can run a DataAnnotation task in one window while the other session fills out a Stripe dashboard in another, with zero collision.
|
|
128
|
+
|
|
129
|
+
Single-instance usage is unchanged and fully backwards compatible — the old per-window assignment is auto-migrated on first load.
|
|
130
|
+
|
|
111
131
|
## Adding to another project
|
|
112
132
|
|
|
113
133
|
Run setup from the new project's directory — the MCP server is already registered globally, this just drops `CLAUDE.md` and tool permissions into the project:
|
package/dist/setup.js
CHANGED
|
@@ -350,8 +350,13 @@ async function runUpdate() {
|
|
|
350
350
|
const existing = readFileSync(claudeMdPath, "utf8");
|
|
351
351
|
if (existing.includes("# Chromeflow")) {
|
|
352
352
|
const before = existing.slice(0, existing.indexOf("# Chromeflow")).trimEnd();
|
|
353
|
-
|
|
354
|
-
|
|
353
|
+
const newContent = (before ? before + "\n\n" : "") + freshContent;
|
|
354
|
+
if (newContent === existing) {
|
|
355
|
+
mdResult = "unchanged";
|
|
356
|
+
} else {
|
|
357
|
+
writeFileSync(claudeMdPath, newContent);
|
|
358
|
+
mdResult = "updated";
|
|
359
|
+
}
|
|
355
360
|
} else {
|
|
356
361
|
writeFileSync(claudeMdPath, existing.trimEnd() + "\n\n" + freshContent);
|
|
357
362
|
mdResult = "appended";
|
|
@@ -360,7 +365,9 @@ async function runUpdate() {
|
|
|
360
365
|
writeFileSync(claudeMdPath, freshContent);
|
|
361
366
|
mdResult = "created";
|
|
362
367
|
}
|
|
363
|
-
if (mdResult === "
|
|
368
|
+
if (mdResult === "unchanged") {
|
|
369
|
+
console.log(`\u2713 ${claudeMdPath} already up to date`);
|
|
370
|
+
} else if (mdResult === "updated") {
|
|
364
371
|
console.log(`\u2713 Updated chromeflow instructions in ${claudeMdPath}`);
|
|
365
372
|
} else if (mdResult === "appended") {
|
|
366
373
|
console.log(`\u2713 Appended chromeflow instructions to ${claudeMdPath}`);
|
package/package.json
CHANGED