auto-webmcp 0.3.20 → 0.3.22

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.
@@ -1874,16 +1874,121 @@ function getMissingRequired(metadata, params) {
1874
1874
  return [];
1875
1875
  return metadata.inputSchema.required.filter((fieldKey) => !(fieldKey in params));
1876
1876
  }
1877
+ function queryShadowAll(root, selector) {
1878
+ const results = [];
1879
+ const hosts = Array.from(root.querySelectorAll?.("*") ?? []);
1880
+ for (const host of hosts) {
1881
+ const sr = host.shadowRoot;
1882
+ if (!sr)
1883
+ continue;
1884
+ results.push(...Array.from(sr.querySelectorAll(selector)));
1885
+ results.push(...queryShadowAll(sr, selector));
1886
+ }
1887
+ return results;
1888
+ }
1889
+ async function fillLookupInput(el, value) {
1890
+ const text = String(value ?? "").trim();
1891
+ const input = el;
1892
+ console.log("[auto-webmcp] fillLookupInput: typing value=", JSON.stringify(text));
1893
+ setReactValue(input, text);
1894
+ input.dispatchEvent(new KeyboardEvent("keydown", { bubbles: true, cancelable: true, key: text.slice(-1) || "" }));
1895
+ input.dispatchEvent(new KeyboardEvent("keyup", { bubbles: true, cancelable: true, key: text.slice(-1) || "" }));
1896
+ const ariaControlsId = el.getAttribute("aria-controls") ?? el.getAttribute("aria-owns");
1897
+ const listbox = await new Promise((resolve) => {
1898
+ const deadline = Date.now() + 3e3;
1899
+ const poll = () => {
1900
+ if (ariaControlsId) {
1901
+ const byId = document.getElementById(ariaControlsId);
1902
+ if (byId) {
1903
+ resolve(byId);
1904
+ return;
1905
+ }
1906
+ const inShadow = queryShadowAll(document.body, `#${CSS.escape(ariaControlsId)}`)[0] ?? null;
1907
+ if (inShadow) {
1908
+ resolve(inShadow);
1909
+ return;
1910
+ }
1911
+ }
1912
+ const lightCandidate = document.querySelector('[role="listbox"]') ?? document.querySelector('[role="option"]')?.closest('[role="listbox"]') ?? null;
1913
+ if (lightCandidate) {
1914
+ resolve(lightCandidate);
1915
+ return;
1916
+ }
1917
+ const shadowCandidate = queryShadowAll(document.body, '[role="listbox"]')[0] ?? null;
1918
+ if (shadowCandidate) {
1919
+ resolve(shadowCandidate);
1920
+ return;
1921
+ }
1922
+ if (Date.now() >= deadline) {
1923
+ resolve(null);
1924
+ return;
1925
+ }
1926
+ setTimeout(poll, 50);
1927
+ };
1928
+ poll();
1929
+ });
1930
+ if (!listbox) {
1931
+ console.warn("[auto-webmcp] fillLookupInput: listbox did not appear after 3s, leaving text as-is");
1932
+ return;
1933
+ }
1934
+ const lightOptions = Array.from(listbox.querySelectorAll('[role="option"]'));
1935
+ const shadowOptions = queryShadowAll(listbox, '[role="option"]');
1936
+ const options = lightOptions.length > 0 ? lightOptions : shadowOptions;
1937
+ console.log("[auto-webmcp] fillLookupInput: listbox has", options.length, "option(s)");
1938
+ const lowerValue = text.toLowerCase();
1939
+ const match = options.find((opt) => {
1940
+ const dataValue = (opt.getAttribute("data-value") ?? "").toLowerCase();
1941
+ const ariaLabel = (opt.getAttribute("aria-label") ?? "").toLowerCase();
1942
+ const optText = (opt.textContent ?? "").trim().toLowerCase();
1943
+ return dataValue === lowerValue || ariaLabel === lowerValue || optText === lowerValue;
1944
+ }) ?? options.find((opt) => {
1945
+ const optText = (opt.textContent ?? "").trim().toLowerCase();
1946
+ return optText.startsWith(lowerValue) || optText.includes(lowerValue);
1947
+ });
1948
+ if (match) {
1949
+ console.log("[auto-webmcp] fillLookupInput: selecting option", match.textContent?.trim());
1950
+ match.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true }));
1951
+ match.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
1952
+ match.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
1953
+ } else {
1954
+ console.warn(
1955
+ "[auto-webmcp] fillLookupInput: no option matched",
1956
+ JSON.stringify(text),
1957
+ "available:",
1958
+ options.map((o) => o.getAttribute("data-value") ?? o.textContent?.trim())
1959
+ );
1960
+ }
1961
+ }
1877
1962
  async function fillComboboxButton(el, value) {
1878
1963
  const text = String(value ?? "").trim();
1879
1964
  console.log("[auto-webmcp] fillComboboxButton: clicking button, value=", JSON.stringify(text));
1965
+ el.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true }));
1966
+ el.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
1880
1967
  el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
1968
+ const ariaControlsId = el.getAttribute("aria-controls");
1881
1969
  const listbox = await new Promise((resolve) => {
1882
1970
  const deadline = Date.now() + 3e3;
1883
1971
  const poll = () => {
1884
- const candidate = document.querySelector('[role="listbox"]') ?? document.querySelector('[role="option"]')?.closest('[role="listbox"]') ?? null;
1885
- if (candidate) {
1886
- resolve(candidate);
1972
+ if (ariaControlsId) {
1973
+ const byId = document.getElementById(ariaControlsId);
1974
+ if (byId) {
1975
+ resolve(byId);
1976
+ return;
1977
+ }
1978
+ const inShadow = queryShadowAll(document.body, `#${CSS.escape(ariaControlsId)}`)[0] ?? null;
1979
+ if (inShadow) {
1980
+ resolve(inShadow);
1981
+ return;
1982
+ }
1983
+ }
1984
+ const lightCandidate = document.querySelector('[role="listbox"]') ?? document.querySelector('[role="option"]')?.closest('[role="listbox"]') ?? null;
1985
+ if (lightCandidate) {
1986
+ resolve(lightCandidate);
1987
+ return;
1988
+ }
1989
+ const shadowCandidate = queryShadowAll(document.body, '[role="listbox"]')[0] ?? null;
1990
+ if (shadowCandidate) {
1991
+ resolve(shadowCandidate);
1887
1992
  return;
1888
1993
  }
1889
1994
  if (Date.now() >= deadline) {
@@ -1895,11 +2000,13 @@ async function fillComboboxButton(el, value) {
1895
2000
  poll();
1896
2001
  });
1897
2002
  if (!listbox) {
1898
- console.warn("[auto-webmcp] fillComboboxButton: listbox did not appear after 1s");
2003
+ console.warn("[auto-webmcp] fillComboboxButton: listbox did not appear after 3s");
1899
2004
  return;
1900
2005
  }
1901
- const options = Array.from(listbox.querySelectorAll('[role="option"]'));
1902
- console.log("[auto-webmcp] fillComboboxButton: listbox has", options.length, "options");
2006
+ const lightOptions = Array.from(listbox.querySelectorAll('[role="option"]'));
2007
+ const shadowOptions = queryShadowAll(listbox, '[role="option"]');
2008
+ const options = lightOptions.length > 0 ? lightOptions : shadowOptions;
2009
+ console.log("[auto-webmcp] fillComboboxButton: listbox has", options.length, "option(s)");
1903
2010
  const lowerValue = text.toLowerCase();
1904
2011
  const match = options.find((opt) => {
1905
2012
  const dataValue = (opt.getAttribute("data-value") ?? "").toLowerCase();
@@ -1908,14 +2015,16 @@ async function fillComboboxButton(el, value) {
1908
2015
  return dataValue === lowerValue || ariaLabel === lowerValue || optText === lowerValue;
1909
2016
  });
1910
2017
  if (match) {
1911
- console.log("[auto-webmcp] fillComboboxButton: clicking option", match.textContent?.trim());
2018
+ console.log("[auto-webmcp] fillComboboxButton: selecting option", match.textContent?.trim());
2019
+ match.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, cancelable: true }));
2020
+ match.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
1912
2021
  match.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
1913
2022
  } else {
1914
2023
  console.warn(
1915
2024
  "[auto-webmcp] fillComboboxButton: no option matched",
1916
2025
  JSON.stringify(text),
1917
2026
  "available:",
1918
- options.map((o) => o.textContent?.trim())
2027
+ options.map((o) => o.getAttribute("data-value") ?? o.textContent?.trim())
1919
2028
  );
1920
2029
  }
1921
2030
  }
@@ -2389,7 +2498,9 @@ async function scanOrphanInputs(config) {
2389
2498
  for (const { key, el } of inputPairs) {
2390
2499
  if (params[key] !== void 0) {
2391
2500
  console.log(`[auto-webmcp] orphan execute: filling key="${key}" value=`, params[key], "element=", el);
2392
- if (el.getAttribute("role") === "combobox" && el.tagName.toLowerCase() === "button") {
2501
+ if (el.getAttribute("role") === "combobox" && el.tagName.toLowerCase() === "input" && (el.getAttribute("aria-autocomplete") === "list" || el.getAttribute("aria-haspopup") === "listbox")) {
2502
+ await fillLookupInput(el, params[key]);
2503
+ } else if (el.getAttribute("role") === "combobox" && el.tagName.toLowerCase() === "button") {
2393
2504
  await fillComboboxButton(el, params[key]);
2394
2505
  } else {
2395
2506
  fillElement(el, params[key]);