chromeflow 0.1.36 → 0.1.38

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 CHANGED
@@ -140,6 +140,9 @@ screenshot to check what happened.
140
140
  2. `get_elements()` to get exact coords → `highlight_region(x,y,w,h,msg)`
141
141
  3. `take_screenshot()` only if you still can't identify the element from DOM queries
142
142
 
143
+ **Multiple elements with the same label** (e.g. many "Remove" buttons):
144
+ `click_element("Remove", nth=3)` — use `nth` (1-based) to target the specific one by order top-to-bottom. Check `get_form_fields` or `get_page_text` first to determine which index corresponds to the right section.
145
+
143
146
  **`fill_input` not found:**
144
147
  1. `click_element(hint)` to focus the field, then retry `fill_input`
145
148
  2. `find_and_highlight(hint, "Click here — I'll fill it in")` (no `valueToType`) then
@@ -173,6 +176,13 @@ for (var i = 0; i < allEls.length; i++) {
173
176
  controls[N].textContent.trim(); // should show selected value
174
177
  ```
175
178
 
179
+ **Page text with large embedded content** (e.g. uploaded log files previewed inline): full-page `get_page_text()` pagination becomes unwieldy. Scope to a specific section instead:
180
+ ```
181
+ get_page_text(selector=".section-3") — scope to a CSS selector
182
+ get_page_text(selector="#upload-form") — scope to an id
183
+ ```
184
+ Use `execute_script("document.querySelectorAll('section').length")` to find structural selectors first.
185
+
176
186
  **Page content rendered as images** (e.g. qualification "Examples" tabs that show PNG screenshots
177
187
  instead of DOM text): `get_page_text()` returns nothing useful. Zoom out and screenshot instead:
178
188
 
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Chromeflow
2
2
 
3
- Browser guidance for Claude Code. When Claude needs you to set up Stripe, grab API keys, configure a third-party service, or do anything in a browser — Chromeflow takes over. It highlights what to click, fills in fields it knows, clicks buttons automatically, and writes captured values straight to your `.env`.
3
+ Browser guidance for Claude Code. When Claude needs you to set up Stripe, grab API keys, configure a third-party service, or do anything in a browser — Chromeflow takes over. It highlights what to click, fills in fields it knows, clicks buttons automatically, uploads files, and writes captured values straight to your `.env`.
4
4
 
5
5
  ## How it works
6
6
 
7
7
  Chromeflow is two things that work together:
8
8
 
9
- - **MCP server** — gives Claude Code a set of browser tools (`open_page`, `click_element`, `fill_input`, `read_element`, `write_to_env`, etc.)
10
- - **Chrome extension** — receives those commands and acts on the active tab (highlights, clicks, fills, captures screenshots)
9
+ - **MCP server** — gives Claude Code a set of browser tools (`open_page`, `click_element`, `fill_form`, `set_file_input`, `read_element`, `write_to_env`, etc.)
10
+ - **Chrome extension** — receives those commands and acts on the active tab (highlights, clicks, fills, uploads files, captures screenshots)
11
11
 
12
12
  Claude drives the flow. You only touch the browser for things that genuinely need you — login, passwords, payment details, personal choices.
13
13
 
@@ -49,6 +49,40 @@ Just ask Claude normally:
49
49
 
50
50
  Claude will navigate, highlight steps, click what it can, pause for anything sensitive, and write values to your `.env` automatically.
51
51
 
52
+ ## What Claude can do
53
+
54
+ | Capability | Tools |
55
+ |------------|-------|
56
+ | Navigate pages, open new tabs | `open_page`, `list_tabs`, `switch_to_tab` |
57
+ | Click buttons and links | `click_element` |
58
+ | Fill single fields | `fill_input` |
59
+ | Fill multiple fields in one call | `fill_form` |
60
+ | Upload files (even hidden inputs) | `set_file_input` |
61
+ | Read page content as text | `get_page_text` |
62
+ | Inspect all form fields | `get_form_fields` |
63
+ | Scroll to a known element | `scroll_to_element` |
64
+ | Highlight elements for the user | `highlight_region`, `find_and_highlight` |
65
+ | Wait for the user to click | `wait_for_click` |
66
+ | Wait for async changes | `wait_for_selector` |
67
+ | Run arbitrary JS | `execute_script` |
68
+ | Capture credentials to `.env` | `read_element`, `write_to_env` |
69
+ | Screenshot (element location only) | `take_screenshot` |
70
+ | Screenshot + save + copy to clipboard | `take_and_copy_screenshot` |
71
+ | Save/restore form state across tabs | `save_page_state`, `restore_page_state` |
72
+ | Show a step-by-step guide panel | `show_guide_panel`, `mark_step_done` |
73
+
74
+ ### File uploads
75
+
76
+ `set_file_input` uses Chrome DevTools Protocol to bypass the browser's file-input script restriction — the same mechanism used by Playwright and Puppeteer. It works even when the `<input type=file>` is hidden behind a custom drag-and-drop zone.
77
+
78
+ ```
79
+ set_file_input("Upload", "/Users/you/Downloads/task.zip")
80
+ ```
81
+
82
+ ### Dedicated Claude window
83
+
84
+ 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.
85
+
52
86
  ## Adding to another project
53
87
 
54
88
  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:
@@ -122,7 +122,8 @@ save_to controls where the PNG is saved: "downloads" (default) saves to ~/Downlo
122
122
  `Get the exact pixel positions of all visible interactive elements on the page (inputs, buttons, links, selects).
123
123
  Use this INSTEAD OF take_screenshot when you need coordinates for highlight_region \u2014 the coordinates are exact DOM values, not estimates.
124
124
  Returns a numbered list with element type, label, and precise x/y/width/height in CSS pixels.
125
- After calling this, use those exact coordinates in highlight_region \u2014 do NOT adjust them.`,
125
+ IMPORTANT: x/y are VIEWPORT-relative (0,0 = top-left of the visible area). Use these exact values directly in highlight_region \u2014 do not add window.scrollY.
126
+ Use get_form_fields instead if you need document y positions or fields below the fold.`,
126
127
  {},
127
128
  async () => {
128
129
  const response = await bridge.request({ type: "get_elements" });
@@ -175,7 +176,7 @@ ${lines.join("\n")}${r.warning ?? ""}` }]
175
176
  Uses Chrome DevTools Protocol to set the file \u2014 the only way to bypass the browser's file-input script restriction.
176
177
  hint: label text or name of the file input (or empty string to target the first file input on the page).
177
178
  file_path: absolute path to the file on the local filesystem (e.g. /Users/you/Downloads/task.zip).
178
- After calling this, call get_page_text to confirm the file was accepted.`,
179
+ After calling this, verify the upload was accepted: use execute_script to check that the input's files.length > 0, or use get_page_text to look for a success indicator (e.g. a Remove button appearing). If not accepted, call set_file_input again \u2014 occasional React timing issues may require a retry.`,
179
180
  {
180
181
  hint: z.string().describe("Label text, name, or surrounding text of the file input. Use empty string to target the first file input on the page."),
181
182
  file_path: z.string().describe("Absolute path to the file to upload (e.g. /Users/you/Downloads/task.zip)")
@@ -17,14 +17,16 @@ function registerFlowTools(server, bridge) {
17
17
  `Click a button, link, or interactive element on the page by its visible text or aria-label.
18
18
  Use this whenever Claude can press a button without needing user input \u2014 e.g. "Save", "Continue", "Create product", "Add pricing", "Confirm", "Next".
19
19
  After clicking, use get_page_text to check the result \u2014 only use take_screenshot if you need pixel positions.
20
- Do NOT use for: elements that require the user to make a personal choice, consent to terms, or enter sensitive data.`,
20
+ Do NOT use for: elements that require the user to make a personal choice, consent to terms, or enter sensitive data.
21
+ When multiple elements share the same label (e.g. many "Remove" buttons), use nth to target a specific one (1 = first/topmost, 2 = second, etc.).`,
21
22
  {
22
23
  textHint: z.string().describe(
23
24
  "The visible label of the button or link (e.g. 'Save product', 'Continue', 'Add a product', 'Create')"
24
- )
25
+ ),
26
+ nth: z.number().int().min(1).optional().describe("Which match to click when multiple elements share the same label (1 = first/topmost, default 1)")
25
27
  },
26
- async ({ textHint }) => {
27
- const response = await bridge.request({ type: "click_element", textHint });
28
+ async ({ textHint, nth }) => {
29
+ const response = await bridge.request({ type: "click_element", textHint, nth });
28
30
  const r = response;
29
31
  if (!r.success) {
30
32
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromeflow",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "Browser guidance MCP server for Claude Code — highlights, clicks, fills, and captures from the web so you don't have to.",
5
5
  "type": "module",
6
6
  "bin": {