auto-webmcp 0.3.18 → 0.3.20

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.
@@ -1794,6 +1794,18 @@ function serializeFormData(form, params, fieldEls) {
1794
1794
  }
1795
1795
  return result;
1796
1796
  }
1797
+ function maybeConvertIsoDate(value, el) {
1798
+ const isoMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
1799
+ if (!isoMatch)
1800
+ return value;
1801
+ if (el instanceof HTMLInputElement && el.type === "date")
1802
+ return value;
1803
+ const fieldHint = (el.name ?? el.id ?? "").toLowerCase();
1804
+ if (!/date/.test(fieldHint))
1805
+ return value;
1806
+ const [, year, month, day] = isoMatch;
1807
+ return `${month}/${day}/${year}`;
1808
+ }
1797
1809
  function fillElement(el, value) {
1798
1810
  if (el instanceof HTMLInputElement) {
1799
1811
  const type = el.type.toLowerCase();
@@ -1808,7 +1820,7 @@ function fillElement(el, value) {
1808
1820
  el.dispatchEvent(new Event("change", { bubbles: true }));
1809
1821
  }
1810
1822
  } else {
1811
- setReactValue(el, String(value ?? ""));
1823
+ setReactValue(el, maybeConvertIsoDate(String(value ?? ""), el));
1812
1824
  }
1813
1825
  } else if (el instanceof HTMLTextAreaElement) {
1814
1826
  setReactValue(el, String(value ?? ""));
@@ -1867,7 +1879,7 @@ async function fillComboboxButton(el, value) {
1867
1879
  console.log("[auto-webmcp] fillComboboxButton: clicking button, value=", JSON.stringify(text));
1868
1880
  el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
1869
1881
  const listbox = await new Promise((resolve) => {
1870
- const deadline = Date.now() + 1e3;
1882
+ const deadline = Date.now() + 3e3;
1871
1883
  const poll = () => {
1872
1884
  const candidate = document.querySelector('[role="listbox"]') ?? document.querySelector('[role="option"]')?.closest('[role="listbox"]') ?? null;
1873
1885
  if (candidate) {
@@ -2025,6 +2037,8 @@ var reAnalysisTimers = /* @__PURE__ */ new Map();
2025
2037
  var RE_ANALYSIS_DEBOUNCE_MS = 300;
2026
2038
  var orphanRescanTimer = null;
2027
2039
  var ORPHAN_RESCAN_DEBOUNCE_MS = 500;
2040
+ var orphanRescanDelayedTimer = null;
2041
+ var ORPHAN_RESCAN_DELAYED_MS = 2e3;
2028
2042
  var registeredOrphanToolNames = /* @__PURE__ */ new Set();
2029
2043
  function scheduleOrphanRescan(config) {
2030
2044
  if (orphanRescanTimer)
@@ -2034,10 +2048,20 @@ function scheduleOrphanRescan(config) {
2034
2048
  void scanOrphanInputs(config);
2035
2049
  }, ORPHAN_RESCAN_DEBOUNCE_MS);
2036
2050
  }
2051
+ function scheduleOrphanRescanDelayed(config) {
2052
+ if (orphanRescanDelayedTimer)
2053
+ clearTimeout(orphanRescanDelayedTimer);
2054
+ orphanRescanDelayedTimer = setTimeout(() => {
2055
+ orphanRescanDelayedTimer = null;
2056
+ void scanOrphanInputs(config);
2057
+ }, ORPHAN_RESCAN_DELAYED_MS);
2058
+ }
2037
2059
  function isInterestingNode(node) {
2038
2060
  const tag = node.tagName.toLowerCase();
2039
2061
  if (tag === "input" || tag === "textarea" || tag === "select")
2040
2062
  return true;
2063
+ if (tag.includes("-"))
2064
+ return true;
2041
2065
  const role = node.getAttribute("role");
2042
2066
  if (role && ARIA_ROLES_TO_SCAN.includes(role))
2043
2067
  return true;
@@ -2118,6 +2142,9 @@ function startObserver(config) {
2118
2142
  }
2119
2143
  if (isInterestingNode(node) && !node.closest("form")) {
2120
2144
  scheduleOrphanRescan(config);
2145
+ if (node.tagName.toLowerCase().includes("-")) {
2146
+ scheduleOrphanRescanDelayed(config);
2147
+ }
2121
2148
  }
2122
2149
  }
2123
2150
  for (const node of mutation.removedNodes) {
@@ -2166,6 +2193,35 @@ var ORPHAN_EXCLUDED_TYPES = /* @__PURE__ */ new Set([
2166
2193
  "button",
2167
2194
  "image"
2168
2195
  ]);
2196
+ function collectShadowOrphanInputs(root, outerHost, visited = /* @__PURE__ */ new Set()) {
2197
+ if (visited.has(root))
2198
+ return [];
2199
+ visited.add(root);
2200
+ const results = [];
2201
+ for (const el of Array.from(root.querySelectorAll("*"))) {
2202
+ const sr = el.shadowRoot;
2203
+ if (!sr)
2204
+ continue;
2205
+ const host = outerHost ?? el;
2206
+ results.push(...collectShadowOrphanInputs(sr, host, visited));
2207
+ }
2208
+ if (root instanceof ShadowRoot) {
2209
+ const selector = 'input, textarea, select, [role="textbox"]:not(input):not(textarea), [role="searchbox"]:not(input):not(textarea), button[role="combobox"]';
2210
+ for (const el of Array.from(root.querySelectorAll(selector))) {
2211
+ if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase()))
2212
+ continue;
2213
+ if (el.closest("form"))
2214
+ continue;
2215
+ const rect = el.getBoundingClientRect();
2216
+ if (rect.width === 0 || rect.height === 0)
2217
+ continue;
2218
+ if (outerHost) {
2219
+ results.push({ el, shadowHost: outerHost });
2220
+ }
2221
+ }
2222
+ }
2223
+ return results;
2224
+ }
2169
2225
  async function scanOrphanInputs(config) {
2170
2226
  if (!isWebMCPSupported())
2171
2227
  return;
@@ -2188,8 +2244,9 @@ async function scanOrphanInputs(config) {
2188
2244
  }
2189
2245
  return true;
2190
2246
  });
2191
- console.log(`[auto-webmcp] orphan: found ${orphanInputs.length} visible orphan input(s)`);
2192
- if (orphanInputs.length === 0)
2247
+ const shadowOrphans = collectShadowOrphanInputs(document.body, null);
2248
+ console.log(`[auto-webmcp] orphan: found ${orphanInputs.length} light-DOM + ${shadowOrphans.length} shadow-DOM orphan inputs`);
2249
+ if (orphanInputs.length === 0 && shadowOrphans.length === 0)
2193
2250
  return;
2194
2251
  const groups = /* @__PURE__ */ new Map();
2195
2252
  for (const input of orphanInputs) {
@@ -2210,6 +2267,24 @@ async function scanOrphanInputs(config) {
2210
2267
  groups.set(foundContainer, []);
2211
2268
  groups.get(foundContainer).push(input);
2212
2269
  }
2270
+ for (const { el, shadowHost } of shadowOrphans) {
2271
+ let container = shadowHost.parentElement;
2272
+ let foundContainer = shadowHost.parentElement ?? document.body;
2273
+ while (container && container !== document.body) {
2274
+ const hasSubmitBtn = container.querySelector(SUBMIT_BTN_GROUPING_SELECTOR) !== null || Array.from(container.querySelectorAll("button")).some(
2275
+ (b) => SUBMIT_TEXT_RE.test(b.textContent ?? "")
2276
+ );
2277
+ if (hasSubmitBtn) {
2278
+ foundContainer = container;
2279
+ break;
2280
+ }
2281
+ container = container.parentElement;
2282
+ }
2283
+ console.log(`[auto-webmcp] orphan (shadow): input (id="${el.id}") via host <${shadowHost.tagName.toLowerCase()}> grouped into container`, foundContainer);
2284
+ if (!groups.has(foundContainer))
2285
+ groups.set(foundContainer, []);
2286
+ groups.get(foundContainer).push(el);
2287
+ }
2213
2288
  console.log(`[auto-webmcp] orphan: ${groups.size} group(s) found`);
2214
2289
  for (const [container, inputs] of groups) {
2215
2290
  const allCandidates = Array.from(