chromeflow 0.2.0 → 0.2.1
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 +4 -1
- package/dist/setup.js +3 -1
- package/dist/tools/flow.js +47 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -48,7 +48,8 @@ Do NOT ask "should I open the browser?" — just do it. The user expects seamles
|
|
|
48
48
|
scroll_page("down") — reveal off-screen content when target location is unknown
|
|
49
49
|
b. Check results with text, not vision:
|
|
50
50
|
get_page_text() — read errors/status after actions
|
|
51
|
-
wait_for_selector(".success") — wait for
|
|
51
|
+
wait_for_selector(".success") — wait for a new element to appear
|
|
52
|
+
wait_for_change(".toast") — wait for an existing element's content to mutate, then read it (uses MutationObserver, cheaper than polling)
|
|
52
53
|
execute_script("document.title") — query DOM state programmatically
|
|
53
54
|
c. When an element can't be found or clicked:
|
|
54
55
|
scroll_page("down") and retry — always try this first
|
|
@@ -167,6 +168,8 @@ screenshot to check what happened.
|
|
|
167
168
|
|
|
168
169
|
**Waiting for async results** (build, save, deploy): `wait_for_selector(selector, timeout)` — never poll with screenshots.
|
|
169
170
|
|
|
171
|
+
**Waiting for an existing region to update** (e.g. click Save, then get the confirmation toast; send a chat message, then get the reply): `wait_for_change(selector)` uses a MutationObserver on the element's subtree and returns its new text content as soon as the mutation settles. Prefer this over `wait_for_selector` + `get_page_text` when the element already exists and you just need its next state — one call instead of two, no polling.
|
|
172
|
+
|
|
170
173
|
**Pre-filling `prompt()` and `confirm()` dialogs**: When a page action will trigger a JS
|
|
171
174
|
dialog (e.g. "Save As" calling `prompt()`), call `set_dialog_response` BEFORE the action:
|
|
172
175
|
```
|
package/dist/setup.js
CHANGED
|
@@ -175,7 +175,9 @@ const CHROMEFLOW_TOOLS = [
|
|
|
175
175
|
// v0.1.46+
|
|
176
176
|
"type_text",
|
|
177
177
|
// v0.1.57+
|
|
178
|
-
"inspect_request_headers"
|
|
178
|
+
"inspect_request_headers",
|
|
179
|
+
// v0.2.1+
|
|
180
|
+
"wait_for_change"
|
|
179
181
|
].map((t) => `mcp__chromeflow__${t}`);
|
|
180
182
|
function patchSettingsLocalJson(cwd) {
|
|
181
183
|
const claudeDir = join(cwd, ".claude");
|
package/dist/tools/flow.js
CHANGED
|
@@ -97,6 +97,53 @@ to 15 seconds so the page is checked gently rather than hammered every 500ms.`,
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
);
|
|
100
|
+
server.tool(
|
|
101
|
+
"wait_for_change",
|
|
102
|
+
`Block until the element matching \`selector\` mutates, then return its text content.
|
|
103
|
+
Uses a MutationObserver \u2014 no polling, no screenshots. Ideal after an action where you expect
|
|
104
|
+
a specific UI region to update: click Save, then wait_for_change(".toast") to capture the
|
|
105
|
+
confirmation. wait_for_change(".chat-messages") after sending a message to get the reply.
|
|
106
|
+
|
|
107
|
+
The element must exist at call time (use wait_for_selector first if needed). After the first
|
|
108
|
+
mutation fires, waits a brief settle window (default 150ms) for the update to batch, then
|
|
109
|
+
returns the element's current text with secrets redacted.
|
|
110
|
+
|
|
111
|
+
Only observes changes within the matched element's subtree. Mutations in deeper shadow roots
|
|
112
|
+
or in sibling elements are not detected. For form inputs whose \`value\` changes without a
|
|
113
|
+
DOM mutation, this won't fire \u2014 use execute_script to read the value directly.`,
|
|
114
|
+
{
|
|
115
|
+
selector: z.string().describe(
|
|
116
|
+
`CSS selector of the element whose changes you want to observe (e.g. '.toast', '.chat-messages', '[role="alert"]')`
|
|
117
|
+
),
|
|
118
|
+
timeout: z.number().optional().describe("Max seconds to wait for a mutation (default 30)"),
|
|
119
|
+
settle: z.number().optional().describe(
|
|
120
|
+
"Milliseconds to wait AFTER the first mutation for subsequent mutations to batch (default 150). Increase to 500-1000 if the page renders in multiple rapid steps."
|
|
121
|
+
)
|
|
122
|
+
},
|
|
123
|
+
async ({ selector, timeout = 30, settle }) => {
|
|
124
|
+
const timeoutMs = timeout * 1e3;
|
|
125
|
+
const settleMs = settle ?? 150;
|
|
126
|
+
const response = await bridge.request(
|
|
127
|
+
{ type: "wait_for_change", selector, timeout: timeoutMs, settle: settleMs },
|
|
128
|
+
timeoutMs + 5e3
|
|
129
|
+
);
|
|
130
|
+
const r = response;
|
|
131
|
+
if (!r.ok) {
|
|
132
|
+
return { content: [{ type: "text", text: r.message ?? `wait_for_change timed out on "${selector}"` }] };
|
|
133
|
+
}
|
|
134
|
+
const preview = (r.text ?? "").slice(0, 5e3);
|
|
135
|
+
return {
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: "text",
|
|
139
|
+
text: `Element "${selector}" changed.
|
|
140
|
+
|
|
141
|
+
${preview}`
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
);
|
|
100
147
|
server.tool(
|
|
101
148
|
"scroll_to_element",
|
|
102
149
|
`Scroll an element into view by CSS selector or label/text match.
|
package/package.json
CHANGED