chromeflow 0.1.31 → 0.1.32
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 +14 -7
- package/dist/setup.js +3 -1
- package/dist/tools/browser.js +4 -3
- package/dist/tools/flow.js +30 -2
- package/dist/tools/highlight.js +11 -8
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -41,8 +41,9 @@ Do NOT ask "should I open the browser?" — just do it. The user expects seamles
|
|
|
41
41
|
a. Claude acts directly:
|
|
42
42
|
click_element("Save") — press buttons/links Claude can press
|
|
43
43
|
get_page_text() or wait_for_selector(".success") — ALWAYS confirm after click; click_element returns after 600ms regardless of outcome
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
fill_form([{label, value}, ...]) — fill multiple fields in one call; prefer over repeated fill_input
|
|
45
|
+
fill_input("Product name", "Pro") — fill a single field (works on React, CodeMirror, and contenteditable)
|
|
46
|
+
clear_overlays() — call this immediately after fill_input/fill_form succeeds
|
|
46
47
|
scroll_to_element("label text") — jump directly to a known field; prefer this over scroll_page when the target is known
|
|
47
48
|
scroll_page("down") — reveal off-screen content when target location is unknown
|
|
48
49
|
b. Check results with text, not vision:
|
|
@@ -51,8 +52,9 @@ Do NOT ask "should I open the browser?" — just do it. The user expects seamles
|
|
|
51
52
|
execute_script("document.title") — query DOM state programmatically
|
|
52
53
|
c. When an element can't be found or clicked:
|
|
53
54
|
scroll_page("down") and retry — always try this first
|
|
54
|
-
get_elements() — get EXACT DOM coords
|
|
55
|
-
highlight_region(
|
|
55
|
+
get_elements() — get EXACT DOM coords when needed
|
|
56
|
+
highlight_region(selector,msg) — highlight by CSS selector (preferred; scrolls element into view automatically)
|
|
57
|
+
highlight_region(x,y,w,h,msg) — highlight by coords only if no selector available (coords go stale on scroll)
|
|
56
58
|
[absolute last resort] take_screenshot() — only if you genuinely can't identify the element from DOM
|
|
57
59
|
d. Pause for the user when needed:
|
|
58
60
|
find_and_highlight(text, msg) — show the user what to do
|
|
@@ -102,9 +104,14 @@ use `take_and_copy_screenshot()` — it saves a PNG to ~/Downloads and copies it
|
|
|
102
104
|
- `get_form_fields()` includes `[type=file]` fields even when they are visually hidden behind
|
|
103
105
|
custom drag-and-drop zones. File fields are marked "manual only" — highlight them and ask
|
|
104
106
|
the user to select the file; they cannot be filled programmatically.
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
- For forms with multiple fields, use `fill_form([{label, value}, ...])` to fill them all
|
|
108
|
+
in a single call. It returns a per-field success/failure report so you can immediately see
|
|
109
|
+
which fields weren't found. Use `fill_input` only for a single field.
|
|
110
|
+
- `fill_input` and `fill_form` work on React-controlled inputs, contenteditable (Stripe,
|
|
111
|
+
Notion), and **CodeMirror 6 editors** — auto-detected. After filling, the value is read
|
|
112
|
+
back and a warning is shown if React did not accept it.
|
|
113
|
+
- After any radio/checkbox click that reveals new fields, call `get_form_fields()` again —
|
|
114
|
+
the inventory will include the new fields and warn if more hidden ones still exist.
|
|
108
115
|
- If a form has collapsible sections, expand them all before calling `get_form_fields()` so
|
|
109
116
|
the field list is complete. Use the `[under: "section name"]` context in each field's entry
|
|
110
117
|
to identify fields by section rather than by index — indices shift when sections expand.
|
package/dist/setup.js
CHANGED
|
@@ -165,7 +165,9 @@ const CHROMEFLOW_TOOLS = [
|
|
|
165
165
|
"save_page_state",
|
|
166
166
|
"restore_page_state",
|
|
167
167
|
// v0.1.25+
|
|
168
|
-
"take_and_copy_screenshot"
|
|
168
|
+
"take_and_copy_screenshot",
|
|
169
|
+
// v0.1.32+
|
|
170
|
+
"fill_form"
|
|
169
171
|
].map((t) => `mcp__chromeflow__${t}`);
|
|
170
172
|
function patchSettingsLocalJson(cwd) {
|
|
171
173
|
const claudeDir = join(cwd, ".claude");
|
package/dist/tools/browser.js
CHANGED
|
@@ -153,9 +153,10 @@ Unlike get_elements, this includes ALL fields (even far below the fold) and is n
|
|
|
153
153
|
async () => {
|
|
154
154
|
const response = await bridge.request({ type: "get_form_fields" });
|
|
155
155
|
if (response.type !== "form_fields_response") throw new Error("Unexpected response");
|
|
156
|
-
const
|
|
156
|
+
const r = response;
|
|
157
|
+
const fields = r.fields;
|
|
157
158
|
if (fields.length === 0) {
|
|
158
|
-
return { content: [{ type: "text", text: "No form fields found on page." }] };
|
|
159
|
+
return { content: [{ type: "text", text: "No form fields found on page." + (r.warning ?? "") }] };
|
|
159
160
|
}
|
|
160
161
|
const lines = fields.map((f) => {
|
|
161
162
|
const val = f.value ? ` [currently: "${f.value}"]` : "";
|
|
@@ -164,7 +165,7 @@ Unlike get_elements, this includes ALL fields (even far below the fold) and is n
|
|
|
164
165
|
});
|
|
165
166
|
return {
|
|
166
167
|
content: [{ type: "text", text: `Form fields (${fields.length} total, sorted top-to-bottom):
|
|
167
|
-
${lines.join("\n")}` }]
|
|
168
|
+
${lines.join("\n")}${r.warning ?? ""}` }]
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
171
|
);
|
package/dist/tools/flow.js
CHANGED
|
@@ -104,8 +104,36 @@ Examples: scroll_to_element("#submit-btn"), scroll_to_element("Billing address")
|
|
|
104
104
|
query: z.string().describe("CSS selector (e.g. '#my-input', '.section-header') or visible text / label to search for")
|
|
105
105
|
},
|
|
106
106
|
async ({ query }) => {
|
|
107
|
-
await bridge.request({ type: "scroll_to_element", query });
|
|
108
|
-
|
|
107
|
+
const response = await bridge.request({ type: "scroll_to_element", query });
|
|
108
|
+
const msg = response.message ?? `Scrolled to element matching "${query}".`;
|
|
109
|
+
return { content: [{ type: "text", text: msg }] };
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
server.tool(
|
|
113
|
+
"fill_form",
|
|
114
|
+
`Fill multiple form fields in a single call by targeting each field by its label text.
|
|
115
|
+
Use this instead of calling fill_input repeatedly \u2014 it fills all fields in one round trip and returns a per-field success report.
|
|
116
|
+
Ideal for forms with many textareas or inputs where each fill would otherwise require a separate tool call.
|
|
117
|
+
fields is an array of {label, value} pairs. label should match the field's visible label, placeholder, or aria-label.`,
|
|
118
|
+
{
|
|
119
|
+
fields: z.array(
|
|
120
|
+
z.object({
|
|
121
|
+
label: z.string().describe("Visible label, placeholder, or aria-label of the field"),
|
|
122
|
+
value: z.string().describe("Value to fill in")
|
|
123
|
+
})
|
|
124
|
+
).describe("List of fields to fill")
|
|
125
|
+
},
|
|
126
|
+
async ({ fields }) => {
|
|
127
|
+
const response = await bridge.request({ type: "fill_form", fields });
|
|
128
|
+
const r = response;
|
|
129
|
+
const lines = r.results.map((f) => `${f.success ? "\u2713" : "\u2717"} "${f.label}": ${f.message}`);
|
|
130
|
+
return {
|
|
131
|
+
content: [{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: `Filled ${r.succeeded}/${r.total} fields:
|
|
134
|
+
${lines.join("\n")}`
|
|
135
|
+
}]
|
|
136
|
+
};
|
|
109
137
|
}
|
|
110
138
|
);
|
|
111
139
|
server.tool(
|
package/dist/tools/highlight.js
CHANGED
|
@@ -36,12 +36,15 @@ function registerHighlightTools(server, bridge) {
|
|
|
36
36
|
);
|
|
37
37
|
server.tool(
|
|
38
38
|
"highlight_region",
|
|
39
|
-
|
|
39
|
+
`Highlight a region on the page with an instructional callout.
|
|
40
|
+
Prefer passing a CSS selector \u2014 the extension will find the element, scroll it into view, and highlight its exact bounds automatically. This is more robust than pixel coordinates, which go stale if the user scrolls.
|
|
41
|
+
Only pass x/y/width/height when you have no selector and already have fresh coordinates from get_elements.`,
|
|
40
42
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
selector: z.string().optional().describe("CSS selector of the element to highlight (e.g. '#upload-zone', '.drop-area'). Preferred over raw coordinates."),
|
|
44
|
+
x: z.number().optional().describe("Left edge in CSS pixels \u2014 only needed if no selector"),
|
|
45
|
+
y: z.number().optional().describe("Top edge in CSS pixels \u2014 only needed if no selector"),
|
|
46
|
+
width: z.number().optional().describe("Width in CSS pixels \u2014 only needed if no selector"),
|
|
47
|
+
height: z.number().optional().describe("Height in CSS pixels \u2014 only needed if no selector"),
|
|
45
48
|
message: z.string().describe(
|
|
46
49
|
"Instruction to show the user in the callout. When the user needs to type something, use a short instruction like 'Type this in the field:' and pass the text as valueToType."
|
|
47
50
|
),
|
|
@@ -49,13 +52,13 @@ function registerHighlightTools(server, bridge) {
|
|
|
49
52
|
`Only use when the user must personally type the value (password, email, personal data). Do NOT use when Claude will auto-fill after the click \u2014 in that case, omit this and use message: "Click here \u2014 I'll fill it in".`
|
|
50
53
|
)
|
|
51
54
|
},
|
|
52
|
-
async ({ x, y, width, height, message, valueToType }) => {
|
|
53
|
-
await bridge.request({ type: "highlight_region", x, y, width, height, message, valueToType });
|
|
55
|
+
async ({ selector, x, y, width, height, message, valueToType }) => {
|
|
56
|
+
await bridge.request({ type: "highlight_region", selector, x, y, width, height, message, valueToType });
|
|
54
57
|
return {
|
|
55
58
|
content: [
|
|
56
59
|
{
|
|
57
60
|
type: "text",
|
|
58
|
-
text: `Region highlighted at (${x}, ${y}) ${width}\xD7${height}.`
|
|
61
|
+
text: selector ? `Highlighted element matching "${selector}".` : `Region highlighted at (${x ?? 0}, ${y ?? 0}) ${width ?? 0}\xD7${height ?? 0}.`
|
|
59
62
|
}
|
|
60
63
|
]
|
|
61
64
|
};
|
package/package.json
CHANGED