auto-webmcp 0.3.9 → 0.3.10

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.
@@ -25,5 +25,5 @@ export declare function analyzeForm(form: HTMLFormElement, override?: FormOverri
25
25
  * Derive ToolMetadata from a group of form controls that are NOT inside a <form>.
26
26
  * Used by discovery.ts's orphan-input scanner for pages like newsletter landing pages.
27
27
  */
28
- export declare function analyzeOrphanInputGroup(container: Element, inputs: Array<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>, submitBtn: HTMLButtonElement | HTMLInputElement | null): ToolMetadata;
28
+ export declare function analyzeOrphanInputGroup(container: Element, inputs: Array<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLElement>, submitBtn: HTMLButtonElement | HTMLInputElement | null): ToolMetadata;
29
29
  //# sourceMappingURL=analyzer.d.ts.map
@@ -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;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"}
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;AAiqBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,WAAW,CAAC,EACvF,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAMd"}
@@ -650,6 +650,19 @@ function resolveNativeControlFallbackKey(control) {
650
650
  }
651
651
  return null;
652
652
  }
653
+ function resolveAriaElementKey(el) {
654
+ if (el.dataset["webmcpName"])
655
+ return sanitizeName(el.dataset["webmcpName"]);
656
+ if (el.id && !AUTO_GENERATED_ID_RE.test(el.id))
657
+ return sanitizeName(el.id);
658
+ const label = el.getAttribute("aria-label");
659
+ if (label)
660
+ return sanitizeName(label);
661
+ const placeholder = el.getAttribute("placeholder");
662
+ if (placeholder)
663
+ return sanitizeName(placeholder);
664
+ return null;
665
+ }
653
666
  function collectAriaControls(form) {
654
667
  const selector = ARIA_ROLES_TO_SCAN.map((r) => `[role="${r}"]`).join(", ");
655
668
  const rawResults = [];
@@ -908,6 +921,22 @@ function buildSchemaFromInputs(inputs) {
908
921
  const processedRadioGroups = /* @__PURE__ */ new Set();
909
922
  const processedCheckboxGroups = /* @__PURE__ */ new Set();
910
923
  for (const control of inputs) {
924
+ if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement) && !(control instanceof HTMLSelectElement)) {
925
+ const fieldKey2 = resolveAriaElementKey(control);
926
+ if (!fieldKey2)
927
+ continue;
928
+ if (!isControlVisible(control))
929
+ continue;
930
+ const prop = { type: "string" };
931
+ prop.title = control.getAttribute("aria-label") ?? fieldKey2;
932
+ const desc2 = control.getAttribute("aria-description") ?? control.getAttribute("aria-describedby") ? null : null;
933
+ if (desc2)
934
+ prop.description = desc2;
935
+ properties[fieldKey2] = prop;
936
+ fieldElements.set(fieldKey2, control);
937
+ required.push(fieldKey2);
938
+ continue;
939
+ }
911
940
  const rawName = control.name;
912
941
  const fieldKey = (rawName ? sanitizeName(rawName) : null) || resolveNativeControlFallbackKey(control);
913
942
  if (!fieldKey)
@@ -1303,10 +1332,17 @@ function fillAriaField(el, value) {
1303
1332
  }
1304
1333
  const htmlEl = el;
1305
1334
  if (htmlEl.isContentEditable) {
1306
- htmlEl.textContent = String(value ?? "");
1335
+ htmlEl.focus();
1336
+ const range = document.createRange();
1337
+ range.selectNodeContents(htmlEl);
1338
+ const sel = window.getSelection();
1339
+ sel?.removeAllRanges();
1340
+ sel?.addRange(range);
1341
+ document.execCommand("insertText", false, String(value ?? ""));
1342
+ } else {
1343
+ el.dispatchEvent(new Event("input", { bubbles: true }));
1344
+ el.dispatchEvent(new Event("change", { bubbles: true }));
1307
1345
  }
1308
- el.dispatchEvent(new Event("input", { bubbles: true }));
1309
- el.dispatchEvent(new Event("change", { bubbles: true }));
1310
1346
  }
1311
1347
  function serializeFormData(form, params, fieldEls) {
1312
1348
  const result = {};
@@ -1579,10 +1615,10 @@ async function scanOrphanInputs(config) {
1579
1615
  return;
1580
1616
  const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button[data-variant="primary"]:not([disabled])';
1581
1617
  const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button[data-variant="primary"]';
1582
- const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search/i;
1618
+ const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search|post|tweet|publish/i;
1583
1619
  const orphanInputs = Array.from(
1584
1620
  document.querySelectorAll(
1585
- "input:not(form input), textarea:not(form textarea), select:not(form select)"
1621
+ 'input:not(form input), textarea:not(form textarea), select:not(form select), [role="textbox"]:not(form [role="textbox"]):not(input):not(textarea), [role="searchbox"]:not(form [role="searchbox"]):not(input):not(textarea), [contenteditable="true"]:not(form [contenteditable="true"]):not(input):not(textarea)'
1586
1622
  )
1587
1623
  ).filter((el) => {
1588
1624
  if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase())) {
@@ -1638,6 +1674,15 @@ async function scanOrphanInputs(config) {
1638
1674
  if (submitBtn)
1639
1675
  console.log(`[auto-webmcp] orphan: using disabled submit button as reference: "${submitBtn.textContent?.trim()}"`);
1640
1676
  }
1677
+ if (!submitBtn) {
1678
+ const containerBtns = Array.from(container.querySelectorAll("button")).filter((b) => {
1679
+ const r = b.getBoundingClientRect();
1680
+ return r.width > 0 && r.height > 0 && !b.disabled && SUBMIT_TEXT_RE.test(b.textContent ?? "");
1681
+ });
1682
+ submitBtn = containerBtns[containerBtns.length - 1] ?? null;
1683
+ if (submitBtn)
1684
+ console.log(`[auto-webmcp] orphan: using text-matched button in container: "${submitBtn.textContent?.trim()}"`);
1685
+ }
1641
1686
  if (!submitBtn) {
1642
1687
  const pageBtns = Array.from(document.querySelectorAll("button")).filter(
1643
1688
  (b) => {
@@ -1657,10 +1702,10 @@ async function scanOrphanInputs(config) {
1657
1702
  const AUTO_ID_RE = /^_r_[0-9a-z]+_$/i;
1658
1703
  for (const el of inputs) {
1659
1704
  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;
1705
+ const key = el.name || el.getAttribute("name") || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") || el.getAttribute("placeholder") || null;
1661
1706
  const safeKey = key ? key.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) : null;
1662
1707
  const matched = !!(safeKey && schemaProps[safeKey]);
1663
- console.log(`[auto-webmcp] orphan: field (name="${el.name}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
1708
+ console.log(`[auto-webmcp] orphan: field (name="${el.name ?? ""}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
1664
1709
  if (matched) {
1665
1710
  inputPairs.push({ key: safeKey, el });
1666
1711
  }