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.
@@ -1820,6 +1820,18 @@ function serializeFormData(form, params, fieldEls) {
1820
1820
  }
1821
1821
  return result;
1822
1822
  }
1823
+ function maybeConvertIsoDate(value, el) {
1824
+ const isoMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
1825
+ if (!isoMatch)
1826
+ return value;
1827
+ if (el instanceof HTMLInputElement && el.type === "date")
1828
+ return value;
1829
+ const fieldHint = (el.name ?? el.id ?? "").toLowerCase();
1830
+ if (!/date/.test(fieldHint))
1831
+ return value;
1832
+ const [, year, month, day] = isoMatch;
1833
+ return `${month}/${day}/${year}`;
1834
+ }
1823
1835
  function fillElement(el, value) {
1824
1836
  if (el instanceof HTMLInputElement) {
1825
1837
  const type = el.type.toLowerCase();
@@ -1834,7 +1846,7 @@ function fillElement(el, value) {
1834
1846
  el.dispatchEvent(new Event("change", { bubbles: true }));
1835
1847
  }
1836
1848
  } else {
1837
- setReactValue(el, String(value ?? ""));
1849
+ setReactValue(el, maybeConvertIsoDate(String(value ?? ""), el));
1838
1850
  }
1839
1851
  } else if (el instanceof HTMLTextAreaElement) {
1840
1852
  setReactValue(el, String(value ?? ""));
@@ -1893,7 +1905,7 @@ async function fillComboboxButton(el, value) {
1893
1905
  console.log("[auto-webmcp] fillComboboxButton: clicking button, value=", JSON.stringify(text));
1894
1906
  el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
1895
1907
  const listbox = await new Promise((resolve) => {
1896
- const deadline = Date.now() + 1e3;
1908
+ const deadline = Date.now() + 3e3;
1897
1909
  const poll = () => {
1898
1910
  const candidate = document.querySelector('[role="listbox"]') ?? document.querySelector('[role="option"]')?.closest('[role="listbox"]') ?? null;
1899
1911
  if (candidate) {
@@ -2051,6 +2063,8 @@ var reAnalysisTimers = /* @__PURE__ */ new Map();
2051
2063
  var RE_ANALYSIS_DEBOUNCE_MS = 300;
2052
2064
  var orphanRescanTimer = null;
2053
2065
  var ORPHAN_RESCAN_DEBOUNCE_MS = 500;
2066
+ var orphanRescanDelayedTimer = null;
2067
+ var ORPHAN_RESCAN_DELAYED_MS = 2e3;
2054
2068
  var registeredOrphanToolNames = /* @__PURE__ */ new Set();
2055
2069
  function scheduleOrphanRescan(config) {
2056
2070
  if (orphanRescanTimer)
@@ -2060,10 +2074,20 @@ function scheduleOrphanRescan(config) {
2060
2074
  void scanOrphanInputs(config);
2061
2075
  }, ORPHAN_RESCAN_DEBOUNCE_MS);
2062
2076
  }
2077
+ function scheduleOrphanRescanDelayed(config) {
2078
+ if (orphanRescanDelayedTimer)
2079
+ clearTimeout(orphanRescanDelayedTimer);
2080
+ orphanRescanDelayedTimer = setTimeout(() => {
2081
+ orphanRescanDelayedTimer = null;
2082
+ void scanOrphanInputs(config);
2083
+ }, ORPHAN_RESCAN_DELAYED_MS);
2084
+ }
2063
2085
  function isInterestingNode(node) {
2064
2086
  const tag = node.tagName.toLowerCase();
2065
2087
  if (tag === "input" || tag === "textarea" || tag === "select")
2066
2088
  return true;
2089
+ if (tag.includes("-"))
2090
+ return true;
2067
2091
  const role = node.getAttribute("role");
2068
2092
  if (role && ARIA_ROLES_TO_SCAN.includes(role))
2069
2093
  return true;
@@ -2144,6 +2168,9 @@ function startObserver(config) {
2144
2168
  }
2145
2169
  if (isInterestingNode(node) && !node.closest("form")) {
2146
2170
  scheduleOrphanRescan(config);
2171
+ if (node.tagName.toLowerCase().includes("-")) {
2172
+ scheduleOrphanRescanDelayed(config);
2173
+ }
2147
2174
  }
2148
2175
  }
2149
2176
  for (const node of mutation.removedNodes) {
@@ -2192,6 +2219,35 @@ var ORPHAN_EXCLUDED_TYPES = /* @__PURE__ */ new Set([
2192
2219
  "button",
2193
2220
  "image"
2194
2221
  ]);
2222
+ function collectShadowOrphanInputs(root, outerHost, visited = /* @__PURE__ */ new Set()) {
2223
+ if (visited.has(root))
2224
+ return [];
2225
+ visited.add(root);
2226
+ const results = [];
2227
+ for (const el of Array.from(root.querySelectorAll("*"))) {
2228
+ const sr = el.shadowRoot;
2229
+ if (!sr)
2230
+ continue;
2231
+ const host = outerHost ?? el;
2232
+ results.push(...collectShadowOrphanInputs(sr, host, visited));
2233
+ }
2234
+ if (root instanceof ShadowRoot) {
2235
+ const selector = 'input, textarea, select, [role="textbox"]:not(input):not(textarea), [role="searchbox"]:not(input):not(textarea), button[role="combobox"]';
2236
+ for (const el of Array.from(root.querySelectorAll(selector))) {
2237
+ if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase()))
2238
+ continue;
2239
+ if (el.closest("form"))
2240
+ continue;
2241
+ const rect = el.getBoundingClientRect();
2242
+ if (rect.width === 0 || rect.height === 0)
2243
+ continue;
2244
+ if (outerHost) {
2245
+ results.push({ el, shadowHost: outerHost });
2246
+ }
2247
+ }
2248
+ }
2249
+ return results;
2250
+ }
2195
2251
  async function scanOrphanInputs(config) {
2196
2252
  if (!isWebMCPSupported())
2197
2253
  return;
@@ -2214,8 +2270,9 @@ async function scanOrphanInputs(config) {
2214
2270
  }
2215
2271
  return true;
2216
2272
  });
2217
- console.log(`[auto-webmcp] orphan: found ${orphanInputs.length} visible orphan input(s)`);
2218
- if (orphanInputs.length === 0)
2273
+ const shadowOrphans = collectShadowOrphanInputs(document.body, null);
2274
+ console.log(`[auto-webmcp] orphan: found ${orphanInputs.length} light-DOM + ${shadowOrphans.length} shadow-DOM orphan inputs`);
2275
+ if (orphanInputs.length === 0 && shadowOrphans.length === 0)
2219
2276
  return;
2220
2277
  const groups = /* @__PURE__ */ new Map();
2221
2278
  for (const input of orphanInputs) {
@@ -2236,6 +2293,24 @@ async function scanOrphanInputs(config) {
2236
2293
  groups.set(foundContainer, []);
2237
2294
  groups.get(foundContainer).push(input);
2238
2295
  }
2296
+ for (const { el, shadowHost } of shadowOrphans) {
2297
+ let container = shadowHost.parentElement;
2298
+ let foundContainer = shadowHost.parentElement ?? document.body;
2299
+ while (container && container !== document.body) {
2300
+ const hasSubmitBtn = container.querySelector(SUBMIT_BTN_GROUPING_SELECTOR) !== null || Array.from(container.querySelectorAll("button")).some(
2301
+ (b) => SUBMIT_TEXT_RE.test(b.textContent ?? "")
2302
+ );
2303
+ if (hasSubmitBtn) {
2304
+ foundContainer = container;
2305
+ break;
2306
+ }
2307
+ container = container.parentElement;
2308
+ }
2309
+ console.log(`[auto-webmcp] orphan (shadow): input (id="${el.id}") via host <${shadowHost.tagName.toLowerCase()}> grouped into container`, foundContainer);
2310
+ if (!groups.has(foundContainer))
2311
+ groups.set(foundContainer, []);
2312
+ groups.get(foundContainer).push(el);
2313
+ }
2239
2314
  console.log(`[auto-webmcp] orphan: ${groups.size} group(s) found`);
2240
2315
  for (const [container, inputs] of groups) {
2241
2316
  const allCandidates = Array.from(