chromeflow 0.12.0 → 0.12.2

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.
Files changed (2) hide show
  1. package/bin/chromeflow.mjs +34 -3
  2. package/package.json +1 -1
@@ -24808,6 +24808,8 @@ var FlowStore = class {
24808
24808
  recalled = /* @__PURE__ */ new Set();
24809
24809
  // origins whose trusted flow was actually shown this session
24810
24810
  lastOrigin;
24811
+ lastAutosaved = null;
24812
+ // most recent autosave, for save_flow to vouch for
24811
24813
  constructor(version2, baseDir, now = Date.now) {
24812
24814
  this.version = version2;
24813
24815
  this.now = now;
@@ -24889,6 +24891,7 @@ var FlowStore = class {
24889
24891
  if (!buf || buf.length === 0) return;
24890
24892
  this.buffer.delete(k);
24891
24893
  this.upsert(k, buf, null);
24894
+ this.lastAutosaved = { key: k, sig: signatureOf(buf) };
24892
24895
  this.pruneExpired();
24893
24896
  this.persist();
24894
24897
  }
@@ -24998,6 +25001,19 @@ ${lines.join("\n")}`;
24998
25001
  if (!k) return { saved: 0, origin: null, message: "No origin known yet \u2014 navigate or interact with a page first." };
24999
25002
  const buf = this.buffer.get(k) ?? [];
25000
25003
  if (buf.length === 0) {
25004
+ if (this.lastAutosaved) {
25005
+ const flows = this.data.origins[this.lastAutosaved.key] ?? [];
25006
+ const f = flows.find((x) => signatureOf(x.steps) === this.lastAutosaved.sig);
25007
+ if (f) {
25008
+ f.tier = "trusted";
25009
+ f.task_label = taskLabel;
25010
+ f.last_verified = this.nowIso();
25011
+ const promotedKey = this.lastAutosaved.key;
25012
+ this.lastAutosaved = null;
25013
+ this.persist();
25014
+ return { saved: f.steps.length, origin: promotedKey, message: `Promoted the just-autosaved flow to trusted: "${taskLabel}" (${f.steps.length} steps) for ${promotedKey}.` };
25015
+ }
25016
+ }
25001
25017
  return { saved: 0, origin: k, message: `Nothing notable buffered for ${k}. Flows capture hard-won steps (a fallback fired, a verified submit, a field needing real keystrokes) \u2014 an ordinary first-try click isn't recorded.` };
25002
25018
  }
25003
25019
  this.buffer.delete(k);
@@ -25139,9 +25155,12 @@ Examples: switch_to_tab({tab: 1}) for the first tab, switch_to_tab({tab: "form"}
25139
25155
  if (response.type !== "tabs_response") throw new Error("Unexpected response");
25140
25156
  const tabs = response.tabs;
25141
25157
  const lines = tabs.map((t) => `${t.index}. ${t.active ? "[active] " : ""}${t.title} \u2014 ${t.url}`);
25158
+ const activeUrl = tabs.find((t) => t.active)?.url;
25159
+ flowStore.noteUrl(activeUrl);
25160
+ const recall = flowStore.recallHint(activeUrl);
25142
25161
  return {
25143
25162
  content: [{ type: "text", text: `Open tabs:
25144
- ${lines.join("\n")}` }]
25163
+ ${lines.join("\n")}${recall}` }]
25145
25164
  };
25146
25165
  }
25147
25166
  );
@@ -26068,7 +26087,7 @@ Current URL: ${activeTab.url}`;
26068
26087
  }, actionUrl);
26069
26088
  }
26070
26089
  flowStore.noteUrl(nowUrl);
26071
- const recall = flowStore.recallHint(nowUrl);
26090
+ const recall = flowStore.recallHint(actionUrl) || flowStore.recallHint(nowUrl);
26072
26091
  const capturable = flowStore.capturableHint(actionUrl);
26073
26092
  if (!r.success) {
26074
26093
  flowStore.observeFailure(actionUrl, selector ?? textHint);
@@ -26412,7 +26431,7 @@ ${lines.join("\n")}${shadowSection}` }] };
26412
26431
  }
26413
26432
 
26414
26433
  // packages/mcp-server/src/index.ts
26415
- var PACKAGE_VERSION = true ? "0.12.0" : "dev";
26434
+ var PACKAGE_VERSION = true ? "0.12.2" : "dev";
26416
26435
  main().catch((err) => {
26417
26436
  console.error("[chromeflow] Fatal error:", err);
26418
26437
  process.exit(1);
@@ -26486,7 +26505,10 @@ ${tabList}`
26486
26505
  );
26487
26506
  const transport = new StdioServerTransport();
26488
26507
  await server.connect(transport);
26508
+ let exited = false;
26489
26509
  const exitClean = (reason) => {
26510
+ if (exited) return;
26511
+ exited = true;
26490
26512
  console.error(`[chromeflow] host disconnected (${reason}), exiting.`);
26491
26513
  try {
26492
26514
  flowStore.flushAll();
@@ -26496,6 +26518,15 @@ ${tabList}`
26496
26518
  };
26497
26519
  process.stdin.on("end", () => exitClean("stdin end"));
26498
26520
  process.stdin.on("close", () => exitClean("stdin close"));
26521
+ process.on("SIGTERM", () => exitClean("SIGTERM"));
26522
+ process.on("SIGINT", () => exitClean("SIGINT"));
26523
+ process.on("SIGHUP", () => exitClean("SIGHUP"));
26524
+ process.on("beforeExit", () => {
26525
+ try {
26526
+ flowStore.flushAll();
26527
+ } catch {
26528
+ }
26529
+ });
26499
26530
  const originalPpid = process.ppid;
26500
26531
  setInterval(() => {
26501
26532
  const ppid = process.ppid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromeflow",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "MCP server for chromeflow \u2014 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",