chromeflow 0.10.2 → 0.10.4
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/bin/chromeflow.mjs +11 -8
- package/package.json +1 -1
package/bin/chromeflow.mjs
CHANGED
|
@@ -25169,7 +25169,8 @@ ${lines.join("\n")}${r.warning ?? ""}${captchaLine}${oauthLine}` }] };
|
|
|
25169
25169
|
**Shadow-piercing helpers are pre-injected** into every script:
|
|
25170
25170
|
- \`$deep(selector, root?)\` \u2014 querySelector that walks open shadow roots
|
|
25171
25171
|
- \`$deepAll(selector, root?)\` \u2014 querySelectorAll equivalent, returns an array
|
|
25172
|
-
- \`shadowDocument\` \u2014 the
|
|
25172
|
+
- \`shadowDocument\` \u2014 the open shadow root with the most interactive elements (buttons, inputs, links), or \`document\` if none. Useful when an SPA mounts ALL of its UI inside a single root shadow host (Outlier-style annotation dashboards): replace every \`document.querySelector*\` call with \`shadowDocument.querySelector*\` and the same code now reaches the SPA's content. On pages with multiple shadow roots (e.g. one for CSS theme vars, one for content), this picks the content root automatically.
|
|
25173
|
+
- \`shadowDocuments\` \u2014 array of ALL open shadow roots on the page (in DOM order). Use when you need to search across multiple shadow roots or when the automatic pick is wrong.
|
|
25173
25174
|
|
|
25174
25175
|
The helpers pierce OPEN shadow roots only \u2014 MAIN world can't reach closed roots. For closed roots, use find_text / get_page_text / click_element / fill_input which pierce both kinds via chrome.dom.openOrClosedShadowRoot.
|
|
25175
25176
|
|
|
@@ -25184,10 +25185,11 @@ When the page navigates mid-script, the response carries \`navigated: true\` and
|
|
|
25184
25185
|
code: external_exports.string().describe(
|
|
25185
25186
|
"JavaScript expression or multi-statement script to evaluate in the page. Top-level `return` is supported."
|
|
25186
25187
|
),
|
|
25187
|
-
tab_query: external_exports.string().optional().describe("Run against a specific tab without changing focus. Same syntax as switch_to_tab: numeric index, URL substring, or title substring. Omit to run against the active tab.")
|
|
25188
|
+
tab_query: external_exports.string().optional().describe("Run against a specific tab without changing focus. Same syntax as switch_to_tab: numeric index, URL substring, or title substring. Omit to run against the active tab."),
|
|
25189
|
+
timeout_ms: external_exports.number().int().min(1e3).optional().describe('Script execution timeout in milliseconds (default 30000). When the script exceeds this limit, execution is terminated via CDP Runtime.terminateExecution and the debugger is released cleanly. Without this, a hung script locks the debugger session indefinitely and every subsequent tool call fails with "Another debugger is already attached." Increase for large DOM traversals inside shadow roots; decrease when you want fast failure on scripts that might hang.')
|
|
25188
25190
|
},
|
|
25189
|
-
async ({ code, tab_query }) => {
|
|
25190
|
-
const response = await bridge.request({ type: "execute_script", code, tab_query });
|
|
25191
|
+
async ({ code, tab_query, timeout_ms }) => {
|
|
25192
|
+
const response = await bridge.request({ type: "execute_script", code, tab_query, timeout_ms });
|
|
25191
25193
|
if (response.type !== "script_response") throw new Error("Unexpected response");
|
|
25192
25194
|
const { result, alert, navigated, reauthorized } = response;
|
|
25193
25195
|
let text = `Result: ${result}`;
|
|
@@ -25680,12 +25682,13 @@ ANTI-BOT SUBMIT CEILING \u2014 synthetic clicks on social/auth platforms (Reddit
|
|
|
25680
25682
|
expect_submit: external_exports.boolean().optional().describe(`Broad anti-bot detector. After the click, watch up to 4s for ANY of: URL change, [role=alert] / [data-sonner-toast] / .toast / .notification / aria-live appearance, [role=dialog] / [aria-modal=true] appearance. Returns success=false with "submit silently rejected (likely anti-bot)" when no signal fires. Use on form submits when the until_* destination isn't known. Ignored when any until_* is set (those are more specific).`),
|
|
25681
25683
|
within_selector: external_exports.string().optional().describe(`Limit candidate matches to this CSS selector's subtree (mirrors find_text's scope_selector). Use to scope nth-counting to one section of a long form: click_element("Approve", nth=1, within_selector="#section-b"). Returns success=false with scope_missed=true if the selector does not match.`),
|
|
25682
25684
|
near_text: external_exports.string().optional().describe("Find the nearest container whose heading starts with this text, then scope candidates to that container's subtree. Ignored when within_selector is set. Useful when the target section has no stable CSS selector but the heading is unique."),
|
|
25683
|
-
try_fiber: external_exports.boolean().optional().describe(`Opt-in last-resort fallback when silently_rejected fires. After the
|
|
25685
|
+
try_fiber: external_exports.boolean().optional().describe(`Opt-in last-resort fallback when silently_rejected fires. After the activity probe reports zero activity, chromeflow walks the React fiber tree from the matched element (up to 12 levels), finds the nearest \`__reactProps$.onClick\` prop, and invokes it with a minimal synthetic event. Now shadow-DOM-aware: when the element is inside a shadow root, the fiber walk searches for React root containers inside that shadow root instead of walking the light DOM. Returns fiber_attempted=true in the response when the path was taken. Do NOT default to this; reserve for repeat silently_rejected on a known-safe React site.`),
|
|
25686
|
+
activity_timeout_ms: external_exports.number().int().min(500).optional().describe(`How long the activity probe watches for DOM mutations, focus changes, URL changes, or alert/toast/modal appearance after the click (default 1500ms). The probe returns early as soon as activity is detected, so the default adds only ~100ms on successful clicks. Increase to 2500-4000ms for buttons that trigger async API calls before producing visible DOM changes (e.g. "Collect Traces" on annotation dashboards). The probe reports "silently_rejected" when zero activity is seen within this window; a higher value reduces false negatives but slows genuine rejection detection.`),
|
|
25684
25687
|
via: external_exports.enum(["auto", "cdp", "fiber"]).optional().describe(`Click dispatch mode. "auto" (default): CDP click, then fiber fallback when try_fiber=true and the activity probe failed. "cdp": CDP click only, no fiber fallback ever. "fiber": skip the CDP bezier + activity probe entirely and invoke __reactProps$.onClick directly. Use "fiber" on React-heavy SPAs (Outlier-style dashboards) where you already know the site is fiber-only \u2014 cuts ~3 seconds of ceremony off the round trip. The fiber path is undocumented React internal access, prefer "auto" until you've confirmed the site needs it.`),
|
|
25685
25688
|
in_dialog: external_exports.boolean().optional().describe(`Scope candidate matches to the topmost open dialog (\`[role=dialog]\`, \`[role=alertdialog]\`, or \`<dialog open>\`), highest z-index wins. Use when Radix/Headless UI dialogs portal to document.body and a generic textHint like "Cancel" would otherwise match the wrong button. Returns scope_missed=true when no dialog is open.`),
|
|
25686
25689
|
dialog_query: external_exports.string().optional().describe(`Scope candidate matches to a specific dialog by heading or aria-label substring. Use when multiple dialogs are open and in_dialog (topmost) would pick the wrong one \u2014 e.g. click_element("Confirm", dialog_query="Delete account"). Mutually exclusive with in_dialog; dialog_query wins when both are set.`)
|
|
25687
25690
|
},
|
|
25688
|
-
async ({ textHint, selector, nth, until_selector, until_url_contains, until_text_contains, until_url_changes, until_timeout_ms, expect_submit, within_selector, near_text, try_fiber, via, in_dialog, dialog_query }) => {
|
|
25691
|
+
async ({ textHint, selector, nth, until_selector, until_url_contains, until_text_contains, until_url_changes, until_timeout_ms, expect_submit, within_selector, near_text, try_fiber, activity_timeout_ms, via, in_dialog, dialog_query }) => {
|
|
25689
25692
|
if (!textHint && !selector || textHint && selector) {
|
|
25690
25693
|
return {
|
|
25691
25694
|
content: [{ type: "text", text: "click_element requires exactly one of textHint or selector" }]
|
|
@@ -25696,7 +25699,7 @@ ANTI-BOT SUBMIT CEILING \u2014 synthetic clicks on social/auth platforms (Reddit
|
|
|
25696
25699
|
let response;
|
|
25697
25700
|
try {
|
|
25698
25701
|
response = await bridge.request(
|
|
25699
|
-
{ type: "click_element", textHint, selector, nth, until_selector, until_url_contains, until_text_contains, until_url_changes, until_timeout_ms, expect_submit, within_selector, near_text, try_fiber, via, in_dialog, dialog_query },
|
|
25702
|
+
{ type: "click_element", textHint, selector, nth, until_selector, until_url_contains, until_text_contains, until_url_changes, until_timeout_ms, expect_submit, within_selector, near_text, try_fiber, activity_timeout_ms, via, in_dialog, dialog_query },
|
|
25700
25703
|
wsTimeout
|
|
25701
25704
|
);
|
|
25702
25705
|
} catch (err) {
|
|
@@ -26060,7 +26063,7 @@ ${lines.join("\n")}${shadowSection}` }] };
|
|
|
26060
26063
|
}
|
|
26061
26064
|
|
|
26062
26065
|
// packages/mcp-server/src/index.ts
|
|
26063
|
-
var PACKAGE_VERSION = true ? "0.10.
|
|
26066
|
+
var PACKAGE_VERSION = true ? "0.10.4" : "dev";
|
|
26064
26067
|
main().catch((err) => {
|
|
26065
26068
|
console.error("[chromeflow] Fatal error:", err);
|
|
26066
26069
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chromeflow",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"description": "MCP server for chromeflow — lets Claude Code or Codex CLI drive your real Chrome browser with sessions intact. Plugin install recommended; npx chromeflow for manual MCP wiring.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/chromeflow.mjs",
|