auto-webmcp 0.3.7 → 0.3.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;AAipBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,EACzE,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAMd"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;AAspBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,EACzE,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAMd"}
@@ -632,11 +632,12 @@ function buildSchema(form) {
632
632
  }
633
633
  return { schema: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object", properties, required }, fieldElements };
634
634
  }
635
+ var AUTO_GENERATED_ID_RE = /^_r_[0-9a-z]+_$|^:[a-z0-9]+:$/i;
635
636
  function resolveNativeControlFallbackKey(control) {
636
637
  const el = control;
637
638
  if (el.dataset["webmcpName"])
638
639
  return sanitizeName(el.dataset["webmcpName"]);
639
- if (control.id)
640
+ if (control.id && !AUTO_GENERATED_ID_RE.test(control.id))
640
641
  return sanitizeName(control.id);
641
642
  const label = control.getAttribute("aria-label");
642
643
  if (label)
@@ -1458,8 +1459,13 @@ async function registerForm(form, config) {
1458
1459
  await registerFormTool(form, metadata, execute);
1459
1460
  registeredForms.add(form);
1460
1461
  registeredFormCount++;
1462
+ const formSubmitBtn = form.querySelector(
1463
+ '[type="submit"], button[data-variant="primary"], button:not([type])'
1464
+ ) ?? null;
1465
+ const pendingBtns = window["__pendingSubmitBtns"] ??= {};
1466
+ pendingBtns[metadata.name] = formSubmitBtn;
1461
1467
  if (config.debug) {
1462
- console.debug(`[auto-webmcp] Registered: ${metadata.name}`, metadata);
1468
+ console.log(`[auto-webmcp] Registered: ${metadata.name}`, metadata);
1463
1469
  }
1464
1470
  emit("form:registered", form, metadata.name);
1465
1471
  }
@@ -1471,7 +1477,7 @@ async function unregisterForm(form, config) {
1471
1477
  await unregisterFormTool(form);
1472
1478
  registeredForms.delete(form);
1473
1479
  if (config.debug) {
1474
- console.debug(`[auto-webmcp] Unregistered: ${name}`);
1480
+ console.log(`[auto-webmcp] Unregistered: ${name}`);
1475
1481
  }
1476
1482
  emit("form:unregistered", form, name);
1477
1483
  }
@@ -1571,8 +1577,8 @@ var ORPHAN_EXCLUDED_TYPES = /* @__PURE__ */ new Set([
1571
1577
  async function scanOrphanInputs(config) {
1572
1578
  if (!isWebMCPSupported())
1573
1579
  return;
1574
- const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button:not([type]):not([disabled])';
1575
- const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button:not([type])';
1580
+ const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button[data-variant="primary"]:not([disabled])';
1581
+ const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button[data-variant="primary"]';
1576
1582
  const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search/i;
1577
1583
  const orphanInputs = Array.from(
1578
1584
  document.querySelectorAll(
@@ -1580,11 +1586,17 @@ async function scanOrphanInputs(config) {
1580
1586
  )
1581
1587
  ).filter((el) => {
1582
1588
  if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase())) {
1589
+ console.log(`[auto-webmcp] orphan: skipping excluded type "${el.type}" (name="${el.name}" id="${el.id}")`);
1583
1590
  return false;
1584
1591
  }
1585
1592
  const rect = el.getBoundingClientRect();
1586
- return rect.width > 0 && rect.height > 0;
1593
+ if (rect.width === 0 || rect.height === 0) {
1594
+ console.log(`[auto-webmcp] orphan: skipping invisible input (name="${el.name}" id="${el.id}")`);
1595
+ return false;
1596
+ }
1597
+ return true;
1587
1598
  });
1599
+ console.log(`[auto-webmcp] orphan: found ${orphanInputs.length} visible orphan input(s)`);
1588
1600
  if (orphanInputs.length === 0)
1589
1601
  return;
1590
1602
  const groups = /* @__PURE__ */ new Map();
@@ -1601,10 +1613,12 @@ async function scanOrphanInputs(config) {
1601
1613
  }
1602
1614
  container = container.parentElement;
1603
1615
  }
1616
+ console.log(`[auto-webmcp] orphan: input (name="${input.name}" id="${input.id}") grouped into container`, foundContainer);
1604
1617
  if (!groups.has(foundContainer))
1605
1618
  groups.set(foundContainer, []);
1606
1619
  groups.get(foundContainer).push(input);
1607
1620
  }
1621
+ console.log(`[auto-webmcp] orphan: ${groups.size} group(s) found`);
1608
1622
  for (const [container, inputs] of groups) {
1609
1623
  const allCandidates = Array.from(
1610
1624
  container.querySelectorAll(SUBMIT_BTN_SELECTOR)
@@ -1613,6 +1627,17 @@ async function scanOrphanInputs(config) {
1613
1627
  return r.width > 0 && r.height > 0;
1614
1628
  });
1615
1629
  let submitBtn = allCandidates[allCandidates.length - 1] ?? null;
1630
+ if (!submitBtn) {
1631
+ const disabledCandidates = Array.from(
1632
+ container.querySelectorAll(SUBMIT_BTN_GROUPING_SELECTOR)
1633
+ ).filter((b) => {
1634
+ const r = b.getBoundingClientRect();
1635
+ return r.width > 0 && r.height > 0 && b.disabled;
1636
+ });
1637
+ submitBtn = disabledCandidates[disabledCandidates.length - 1] ?? null;
1638
+ if (submitBtn)
1639
+ console.log(`[auto-webmcp] orphan: using disabled submit button as reference: "${submitBtn.textContent?.trim()}"`);
1640
+ }
1616
1641
  if (!submitBtn) {
1617
1642
  const pageBtns = Array.from(document.querySelectorAll("button")).filter(
1618
1643
  (b) => {
@@ -1621,28 +1646,50 @@ async function scanOrphanInputs(config) {
1621
1646
  }
1622
1647
  );
1623
1648
  submitBtn = pageBtns[pageBtns.length - 1] ?? null;
1649
+ if (submitBtn)
1650
+ console.log(`[auto-webmcp] orphan: using page-wide fallback submit button: "${submitBtn.textContent?.trim()}"`);
1624
1651
  }
1652
+ console.log(`[auto-webmcp] orphan: submit button for group:`, submitBtn ? `"${submitBtn.textContent?.trim()}" disabled=${submitBtn.disabled}` : "none");
1625
1653
  const metadata = analyzeOrphanInputGroup(container, inputs, submitBtn);
1654
+ console.log(`[auto-webmcp] orphan: tool="${metadata.name}" schema keys:`, Object.keys(metadata.inputSchema.properties));
1626
1655
  const inputPairs = [];
1627
1656
  const schemaProps = metadata.inputSchema.properties;
1657
+ const AUTO_ID_RE = /^_r_[0-9a-z]+_$/i;
1628
1658
  for (const el of inputs) {
1629
- const key = el.name || el.dataset["webmcpName"] || el.id || el.getAttribute("aria-label") || null;
1659
+ const id = el.id && !AUTO_ID_RE.test(el.id) ? el.id : null;
1660
+ const key = el.name || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") || (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement ? el.placeholder || null : null) || null;
1630
1661
  const safeKey = key ? key.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) : null;
1631
- if (safeKey && schemaProps[safeKey]) {
1662
+ const matched = !!(safeKey && schemaProps[safeKey]);
1663
+ console.log(`[auto-webmcp] orphan: field (name="${el.name}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
1664
+ if (matched) {
1632
1665
  inputPairs.push({ key: safeKey, el });
1633
1666
  }
1634
1667
  }
1668
+ console.log(`[auto-webmcp] orphan: ${inputPairs.length}/${inputs.length} input(s) mapped to schema keys`);
1669
+ if (inputPairs.length === 0) {
1670
+ console.log(`[auto-webmcp] orphan: skipping group "${metadata.name}" \u2014 no inputs mapped to schema keys`);
1671
+ continue;
1672
+ }
1635
1673
  const toolName = metadata.name;
1636
1674
  const execute = async (params) => {
1675
+ console.log(`[auto-webmcp] orphan execute: tool="${toolName}" params=`, params);
1676
+ console.log(`[auto-webmcp] orphan execute: inputPairs=`, inputPairs.map((p) => p.key));
1637
1677
  for (const { key, el } of inputPairs) {
1638
1678
  if (params[key] !== void 0) {
1679
+ console.log(`[auto-webmcp] orphan execute: filling key="${key}" value=`, params[key], "element=", el);
1639
1680
  fillElement(el, params[key]);
1681
+ console.log(`[auto-webmcp] orphan execute: after fill, element value=`, el.value);
1682
+ } else {
1683
+ console.log(`[auto-webmcp] orphan execute: key="${key}" not in params, skipping`);
1640
1684
  }
1641
1685
  }
1642
1686
  window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
1643
- if (!config.autoSubmit) {
1687
+ const shouldAutoSubmit = config.autoSubmit || !!submitBtn?.hasAttribute("toolautosubmit") || submitBtn instanceof HTMLElement && submitBtn.dataset["webmcpAutosubmit"] !== void 0 || container.hasAttribute("toolautosubmit") || container instanceof HTMLElement && container.dataset["webmcpAutosubmit"] !== void 0;
1688
+ if (!shouldAutoSubmit) {
1689
+ console.log(`[auto-webmcp] orphan execute: autoSubmit=false, returning without clicking submit`);
1644
1690
  return { content: [{ type: "text", text: "Fields filled. Ready to submit." }] };
1645
1691
  }
1692
+ console.log(`[auto-webmcp] orphan execute: polling for enabled submit button (up to 2s)...`);
1646
1693
  let btn = null;
1647
1694
  const deadline = Date.now() + 2e3;
1648
1695
  while (Date.now() < deadline) {
@@ -1660,8 +1707,10 @@ async function scanOrphanInputs(config) {
1660
1707
  await new Promise((r) => setTimeout(r, 100));
1661
1708
  }
1662
1709
  if (!btn) {
1710
+ console.warn(`[auto-webmcp] orphan execute: submit button still disabled after 2s`);
1663
1711
  return { content: [{ type: "text", text: "Fields filled but the submit button is still disabled. The page may require additional input before submitting." }] };
1664
1712
  }
1713
+ console.log(`[auto-webmcp] orphan execute: clicking submit button "${btn.textContent?.trim()}"`);
1665
1714
  btn.click();
1666
1715
  return { content: [{ type: "text", text: "Fields filled and form submitted." }] };
1667
1716
  };
@@ -1676,8 +1725,10 @@ async function scanOrphanInputs(config) {
1676
1725
  toolDef.annotations = metadata.annotations;
1677
1726
  }
1678
1727
  await navigator.modelContext.registerTool(toolDef);
1728
+ const pendingBtns = window["__pendingSubmitBtns"] ??= {};
1729
+ pendingBtns[metadata.name] = submitBtn;
1679
1730
  if (config.debug) {
1680
- console.debug(`[auto-webmcp] Orphan tool registered: ${metadata.name}`, metadata);
1731
+ console.log(`[auto-webmcp] Orphan tool registered: ${metadata.name}`, metadata);
1681
1732
  }
1682
1733
  } catch {
1683
1734
  }