auto-webmcp 0.2.5 → 0.2.7

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.
@@ -173,7 +173,7 @@ function buildStringSchema(input) {
173
173
  return prop;
174
174
  }
175
175
  function mapSelectElement(select) {
176
- const filtered = Array.from(select.options).filter((o) => o.value !== "");
176
+ const filtered = Array.from(select.options).filter((o) => o.value !== "" && !o.disabled);
177
177
  if (filtered.length === 0) {
178
178
  return { type: "string" };
179
179
  }
@@ -435,6 +435,12 @@ function resolveNativeControlFallbackKey(control) {
435
435
  const label = control.getAttribute("aria-label");
436
436
  if (label)
437
437
  return sanitizeName(label);
438
+ if ((control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) && control.placeholder?.trim()) {
439
+ return sanitizeName(control.placeholder.trim());
440
+ }
441
+ if (control instanceof HTMLInputElement && control.type !== "text") {
442
+ return control.type;
443
+ }
438
444
  return null;
439
445
  }
440
446
  function collectAriaControls(form) {
@@ -519,6 +525,9 @@ function inferFieldTitle(control) {
519
525
  return humanizeName(control.name);
520
526
  if (control.id)
521
527
  return humanizeName(control.id);
528
+ if ((control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) && control.placeholder?.trim()) {
529
+ return control.placeholder.trim();
530
+ }
522
531
  return "";
523
532
  }
524
533
  function inferFieldDescription(control) {
@@ -659,6 +668,7 @@ init_registry();
659
668
  var pendingExecutions = /* @__PURE__ */ new WeakMap();
660
669
  var lastParams = /* @__PURE__ */ new WeakMap();
661
670
  var formFieldElements = /* @__PURE__ */ new WeakMap();
671
+ var pendingWarnings = /* @__PURE__ */ new WeakMap();
662
672
  var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
663
673
  var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
664
674
  var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
@@ -673,22 +683,36 @@ function buildExecuteHandler(form, config, toolName, metadata) {
673
683
  return new Promise((resolve, reject) => {
674
684
  pendingExecutions.set(form, { resolve, reject });
675
685
  if (config.autoSubmit || form.hasAttribute("toolautosubmit") || form.dataset["webmcpAutosubmit"] !== void 0) {
676
- setTimeout(() => {
677
- fillFormFields(form, params);
678
- let submitForm = form;
679
- if (!form.isConnected) {
680
- const liveBtn = document.querySelector(
681
- 'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
682
- );
683
- const found = liveBtn?.closest("form");
684
- if (found) {
685
- submitForm = found;
686
- pendingExecutions.set(submitForm, { resolve, reject });
687
- attachSubmitInterceptor(submitForm, toolName);
686
+ waitForDomStable(form).then(async () => {
687
+ try {
688
+ fillFormFields(form, params);
689
+ for (let attempt = 0; attempt < 2; attempt++) {
690
+ const reset = getResetFields(form, params, formFieldElements.get(form));
691
+ if (reset.length === 0)
692
+ break;
693
+ fillFormFields(form, params);
694
+ await waitForDomStable(form, 400, 100);
695
+ }
696
+ let submitForm = form;
697
+ if (!form.isConnected) {
698
+ const liveBtn = document.querySelector(
699
+ 'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
700
+ );
701
+ const found = liveBtn?.closest("form");
702
+ if (found) {
703
+ submitForm = found;
704
+ pendingExecutions.set(submitForm, { resolve, reject });
705
+ attachSubmitInterceptor(submitForm, toolName);
706
+ }
688
707
  }
708
+ const missing = getMissingRequired(metadata, params);
709
+ if (missing.length > 0)
710
+ pendingWarnings.set(submitForm, missing);
711
+ submitForm.requestSubmit();
712
+ } catch (err) {
713
+ reject(err instanceof Error ? err : new Error(String(err)));
689
714
  }
690
- submitForm.requestSubmit();
691
- }, 300);
715
+ });
692
716
  }
693
717
  });
694
718
  };
@@ -704,7 +728,10 @@ function attachSubmitInterceptor(form, toolName) {
704
728
  const { resolve } = pending;
705
729
  pendingExecutions.delete(form);
706
730
  const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
707
- const text = `Form submitted. Fields: ${JSON.stringify(formData)}`;
731
+ const missing = pendingWarnings.get(form);
732
+ pendingWarnings.delete(form);
733
+ const warningText = missing?.length ? ` Note: required fields were not filled: ${missing.join(", ")}.` : "";
734
+ const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
708
735
  const result = { content: [{ type: "text", text }] };
709
736
  if (e.agentInvoked && typeof e.respondWith === "function") {
710
737
  e.preventDefault();
@@ -910,6 +937,50 @@ function fillElement(el, value) {
910
937
  fillAriaField(el, value);
911
938
  }
912
939
  }
940
+ function waitForDomStable(form, maxMs = 800, debounceMs = 150) {
941
+ return new Promise((resolve) => {
942
+ let settled = false;
943
+ let debounceTimer = null;
944
+ const settle = () => {
945
+ if (settled)
946
+ return;
947
+ settled = true;
948
+ observer2.disconnect();
949
+ if (debounceTimer !== null)
950
+ clearTimeout(debounceTimer);
951
+ resolve();
952
+ };
953
+ const observer2 = new MutationObserver(() => {
954
+ if (debounceTimer !== null)
955
+ clearTimeout(debounceTimer);
956
+ debounceTimer = setTimeout(settle, debounceMs);
957
+ });
958
+ observer2.observe(form, { childList: true, subtree: true, attributes: true, characterData: true });
959
+ setTimeout(settle, maxMs);
960
+ debounceTimer = setTimeout(settle, debounceMs);
961
+ });
962
+ }
963
+ function getResetFields(form, params, fieldEls) {
964
+ const reset = [];
965
+ for (const [key, expected] of Object.entries(params)) {
966
+ const el = findNativeField(form, key) ?? (fieldEls?.get(key) ?? null);
967
+ if (!el)
968
+ continue;
969
+ if (el instanceof HTMLInputElement && el.type === "checkbox") {
970
+ if (el.checked !== Boolean(expected))
971
+ reset.push(key);
972
+ } else if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
973
+ if (el.value !== String(expected ?? ""))
974
+ reset.push(key);
975
+ }
976
+ }
977
+ return reset;
978
+ }
979
+ function getMissingRequired(metadata, params) {
980
+ if (!metadata?.inputSchema?.required?.length)
981
+ return [];
982
+ return metadata.inputSchema.required.filter((fieldKey) => !(fieldKey in params));
983
+ }
913
984
 
914
985
  // src/enhancer.ts
915
986
  async function enrichMetadata(metadata, enhancer) {