chromeflow 0.1.23 → 0.1.25

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/dist/setup.js CHANGED
@@ -156,7 +156,16 @@ const CHROMEFLOW_TOOLS = [
156
156
  "mark_step_done",
157
157
  "find_and_highlight",
158
158
  "highlight_region",
159
- "show_guide_panel"
159
+ "show_guide_panel",
160
+ // v0.1.23+
161
+ "switch_to_tab",
162
+ "list_tabs",
163
+ "get_form_fields",
164
+ "scroll_to_element",
165
+ "save_page_state",
166
+ "restore_page_state",
167
+ // v0.1.25+
168
+ "take_and_copy_screenshot"
160
169
  ].map((t) => `mcp__chromeflow__${t}`);
161
170
  function patchSettingsLocalJson(cwd) {
162
171
  const claudeDir = join(cwd, ".claude");
@@ -311,16 +320,40 @@ async function runUninstall() {
311
320
  }
312
321
  console.log("\nDone. Restart Claude Code to complete removal.\n");
313
322
  }
323
+ async function fetchLatestClaudeMd() {
324
+ try {
325
+ const res = await fetch("https://unpkg.com/chromeflow@latest/CLAUDE.md");
326
+ if (res.ok) return await res.text();
327
+ } catch {
328
+ }
329
+ return getClaudeMdContent();
330
+ }
314
331
  async function runUpdate() {
315
332
  const cwd = process.cwd();
316
333
  console.log("\nChromeflow Update\n" + "\u2500".repeat(40));
317
- const mdResult = patchProjectClaudeMd(cwd, true);
334
+ const freshContent = await fetchLatestClaudeMd();
335
+ const claudeMdPath = join(cwd, "CLAUDE.md");
336
+ let mdResult;
337
+ if (existsSync(claudeMdPath)) {
338
+ const existing = readFileSync(claudeMdPath, "utf8");
339
+ if (existing.includes("# Chromeflow")) {
340
+ const before = existing.slice(0, existing.indexOf("# Chromeflow")).trimEnd();
341
+ writeFileSync(claudeMdPath, (before ? before + "\n\n" : "") + freshContent);
342
+ mdResult = "updated";
343
+ } else {
344
+ writeFileSync(claudeMdPath, existing.trimEnd() + "\n\n" + freshContent);
345
+ mdResult = "appended";
346
+ }
347
+ } else {
348
+ writeFileSync(claudeMdPath, freshContent);
349
+ mdResult = "created";
350
+ }
318
351
  if (mdResult === "updated") {
319
- console.log(`\u2713 Updated chromeflow instructions in ${join(cwd, "CLAUDE.md")}`);
352
+ console.log(`\u2713 Updated chromeflow instructions in ${claudeMdPath}`);
320
353
  } else if (mdResult === "appended") {
321
- console.log(`\u2713 Appended chromeflow instructions to ${join(cwd, "CLAUDE.md")}`);
354
+ console.log(`\u2713 Appended chromeflow instructions to ${claudeMdPath}`);
322
355
  } else {
323
- console.log(`\u2713 Created ${join(cwd, "CLAUDE.md")}`);
356
+ console.log(`\u2713 Created ${claudeMdPath}`);
324
357
  }
325
358
  const settingsResult = patchSettingsLocalJson(cwd);
326
359
  if (settingsResult === "already-present") {
@@ -1,4 +1,8 @@
1
1
  import { z } from "zod";
2
+ import { writeFileSync, copyFileSync } from "fs";
3
+ import { tmpdir, homedir } from "os";
4
+ import { join } from "path";
5
+ import { execSync } from "child_process";
2
6
  function registerBrowserTools(server, bridge) {
3
7
  server.tool(
4
8
  "open_page",
@@ -68,6 +72,40 @@ ${lines.join("\n")}` }]
68
72
  };
69
73
  }
70
74
  );
75
+ server.tool(
76
+ "take_and_copy_screenshot",
77
+ `Take a screenshot, copy it to the system clipboard, and save it as a PNG file.
78
+ Use this when you need to share, upload, or keep a screenshot outside of Claude.
79
+ The image is always copied to the clipboard so you can immediately paste it anywhere.
80
+ save_to controls where the file is saved: "downloads" (default) saves to ~/Downloads, "cwd" saves to Claude's current working directory.`,
81
+ {
82
+ save_to: z.enum(["downloads", "cwd"]).optional().describe(`Where to save the PNG file: "downloads" (~/Downloads, default) or "cwd" (Claude's current working directory)`)
83
+ },
84
+ async ({ save_to = "downloads" }) => {
85
+ const response = await bridge.request({ type: "screenshot" });
86
+ if (response.type !== "screenshot_response") throw new Error("Unexpected response from extension");
87
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
88
+ const filename = `chromeflow-${timestamp}.png`;
89
+ const imageBuffer = Buffer.from(response.image, "base64");
90
+ const tmpPath = join(tmpdir(), filename);
91
+ writeFileSync(tmpPath, imageBuffer);
92
+ const savePath = save_to === "cwd" ? join(process.cwd(), filename) : join(homedir(), "Downloads", filename);
93
+ copyFileSync(tmpPath, savePath);
94
+ let clipboardNote = "";
95
+ try {
96
+ execSync(`osascript -e 'set the clipboard to (read (POSIX file "${tmpPath}") as \xABclass PNGf\xBB)'`);
97
+ clipboardNote = "Copied to clipboard. ";
98
+ } catch {
99
+ clipboardNote = "";
100
+ }
101
+ return {
102
+ content: [
103
+ { type: "image", data: response.image, mimeType: "image/png" },
104
+ { type: "text", text: `${clipboardNote}Saved to ${savePath}` }
105
+ ]
106
+ };
107
+ }
108
+ );
71
109
  server.tool(
72
110
  "clear_overlays",
73
111
  "Remove all highlights and callout annotations from the current page. Does NOT remove the guide panel \u2014 the guide panel persists until the next flow starts.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromeflow",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
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": {